diff options
68 files changed, 2151 insertions, 2338 deletions
@@ -15,3 +15,4 @@ android/bin android/libs android/gen android/local.properties +doc/source @@ -133,19 +133,16 @@ $(OUT)/cmapdump.o : pdf/pdf_cmap.c pdf/pdf_cmap_parse.c # --- Tools and Apps --- -MU_APPS := $(addprefix $(OUT)/, mudraw mupdfclean mupdfextract mupdfinfo mupdfshow) +MUDRAW := $(addprefix $(OUT)/, mudraw) +$(MUDRAW) : $(FITZ_LIB) $(THIRD_LIBS) -$(MU_APPS) : $(FITZ_LIB) $(THIRD_LIBS) - -BUSY_SRC := $(notdir $(wildcard apps/mubusy_*.c)) -BUSY_APP := $(addprefix $(OUT)/, mubusy) -$(BUSY_APP) : $(addprefix $(OUT)/, $(BUSY_SRC:%.c=%.o)) -$(BUSY_APP) : $(FITZ_LIB) $(THIRD_LIBS) +MUBUSY := $(addprefix $(OUT)/, mubusy) +$(MUBUSY) : $(addprefix $(OUT)/, mupdfclean.o mupdfextract.o mupdfinfo.o mupdfposter.o mupdfshow.o) $(FITZ_LIB) $(THIRD_LIBS) ifeq "$(NOX11)" "" -MUPDF := $(OUT)/mupdf -$(MUPDF) : $(FITZ_LIB) $(THIRD_LIBS) -$(MUPDF) : $(addprefix $(OUT)/, x11_main.o x11_image.o pdfapp.o) +MUVIEW := $(OUT)/mupdf +$(MUVIEW) : $(FITZ_LIB) $(THIRD_LIBS) +$(MUVIEW) : $(addprefix $(OUT)/, x11_main.o x11_image.o pdfapp.o) $(LINK_CMD) $(X11_LIBS) endif @@ -167,16 +164,16 @@ libdir ?= $(prefix)/lib incdir ?= $(prefix)/include mandir ?= $(prefix)/share/man -install: $(FITZ_LIB) $(MU_APPS) $(MUPDF) +install: $(FITZ_LIB) $(MUVIEW) $(MUDRAW) $(MUBUSY) install -d $(bindir) $(libdir) $(incdir) $(mandir)/man1 install $(FITZ_LIB) $(libdir) install fitz/memento.h fitz/fitz.h pdf/mupdf.h xps/muxps.h cbz/mucbz.h $(incdir) - install $(MU_APPS) $(MUPDF) $(bindir) + install $(MUVIEW) $(MUDRAW) $(MUBUSY) $(bindir) install $(wildcard apps/man/*.1) $(mandir)/man1 # --- Clean and Default --- -all: $(THIRD_LIBS) $(FITZ_LIB) $(MU_APPS) $(MUPDF) $(BUSY_APP) +all: $(THIRD_LIBS) $(FITZ_LIB) $(MUVIEW) $(MUDRAW) $(MUBUSY) clean: rm -rf $(OUT) diff --git a/android/jni/Core.mk b/android/jni/Core.mk index dbe0e39d..cea16e74 100644 --- a/android/jni/Core.mk +++ b/android/jni/Core.mk @@ -73,7 +73,6 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/draw/draw_path.c \ $(MY_ROOT)/draw/draw_simple_scale.c \ $(MY_ROOT)/draw/draw_unpack.c \ - $(MY_ROOT)/pdf/base_object.c \ $(MY_ROOT)/pdf/pdf_annot.c \ $(MY_ROOT)/pdf/pdf_cmap.c \ $(MY_ROOT)/pdf/pdf_cmap_load.c \ @@ -90,6 +89,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/pdf/pdf_lex.c \ $(MY_ROOT)/pdf/pdf_metrics.c \ $(MY_ROOT)/pdf/pdf_nametree.c \ + $(MY_ROOT)/pdf/pdf_object.c \ $(MY_ROOT)/pdf/pdf_outline.c \ $(MY_ROOT)/pdf/pdf_page.c \ $(MY_ROOT)/pdf/pdf_parse.c \ @@ -102,6 +102,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/pdf/pdf_unicode.c \ $(MY_ROOT)/pdf/pdf_xobject.c \ $(MY_ROOT)/pdf/pdf_xref.c \ + $(MY_ROOT)/pdf/pdf_xref_aux.c \ $(MY_ROOT)/xps/xps_common.c \ $(MY_ROOT)/xps/xps_doc.c \ $(MY_ROOT)/xps/xps_glyphs.c \ diff --git a/android/src/com/artifex/mupdf/MuPDFActivity.java b/android/src/com/artifex/mupdf/MuPDFActivity.java index bdc1971f..5696ea0b 100644 --- a/android/src/com/artifex/mupdf/MuPDFActivity.java +++ b/android/src/com/artifex/mupdf/MuPDFActivity.java @@ -289,6 +289,11 @@ public class MuPDFActivity extends Activity // no longer appropriate, tell the page to remove HQ ((PageView)v).removeHq(); } + + @Override + protected void onNotInUse(View v) { + ((PageView)v).releaseResources(); + } }; mDocView.setAdapter(new MuPDFPageAdapter(this, core)); diff --git a/android/src/com/artifex/mupdf/PageView.java b/android/src/com/artifex/mupdf/PageView.java index 123d5037..7a0fcfa9 100644 --- a/android/src/com/artifex/mupdf/PageView.java +++ b/android/src/com/artifex/mupdf/PageView.java @@ -81,6 +81,36 @@ public abstract class PageView extends ViewGroup { protected abstract void drawPage(Bitmap bm, int sizeX, int sizeY, int patchX, int patchY, int patchWidth, int patchHeight); protected abstract LinkInfo[] getLinkInfo(); + public void releaseResources() { + // Cancel pending render task + if (mDrawEntire != null) { + mDrawEntire.cancel(true); + mDrawEntire = null; + } + + if (mDrawPatch != null) { + mDrawPatch.cancel(true); + mDrawPatch = null; + } + + mIsBlank = true; + mPageNumber = 0; + + if (mSize == null) + mSize = mParentSize; + + if (mEntire != null) + mEntire.setImageBitmap(null); + + if (mPatch != null) + mPatch.setImageBitmap(null); + + if (mBusyIndicator != null) { + removeView(mBusyIndicator); + mBusyIndicator = null; + } + } + public void blank(int page) { // Cancel pending render task if (mDrawEntire != null) { @@ -88,6 +118,11 @@ public abstract class PageView extends ViewGroup { mDrawEntire = null; } + if (mDrawPatch != null) { + mDrawPatch.cancel(true); + mDrawPatch = null; + } + mIsBlank = true; mPageNumber = page; diff --git a/android/src/com/artifex/mupdf/ReaderView.java b/android/src/com/artifex/mupdf/ReaderView.java index 76bf0eee..fc031471 100644 --- a/android/src/com/artifex/mupdf/ReaderView.java +++ b/android/src/com/artifex/mupdf/ReaderView.java @@ -115,6 +115,8 @@ public class ReaderView extends AdapterView<Adapter> protected void onUnsettle(View v) {}; + protected void onNotInUse(View v) {}; + public View getDisplayedView() { return mChildViews.get(mCurrent); } @@ -342,6 +344,7 @@ public class ReaderView extends AdapterView<Adapter> int ai = childIndices[i]; if (ai < mCurrent - 1 || ai > mCurrent + 1) { View v = mChildViews.get(ai); + onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); mChildViews.remove(ai); @@ -355,7 +358,7 @@ public class ReaderView extends AdapterView<Adapter> int numChildren = mChildViews.size(); for (int i = 0; i < numChildren; i++) { View v = mChildViews.valueAt(i); - postUnsettle(v); + onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); } diff --git a/apps/man/mubusy.1 b/apps/man/mubusy.1 new file mode 100644 index 00000000..435dba4d --- /dev/null +++ b/apps/man/mubusy.1 @@ -0,0 +1,77 @@ +.TH "MUBUSY" "1" "May 10, 2012" +.\" Please adjust this date whenever revising the manpage. +.\" no hyphenation +.nh +.\" adjust left +.ad l +.SH NAME +mubusy \- all purpose tool for dealing with PDF files +.SH SYNOPSIS +mubusy <sub-command> [options] +.SH DESCRIPTION +mubusy is a tool based on MuPDF for dealing with PDF files in various manners. +There are several sub commands available, as described below. +.SH CLEAN +mubusy clean [options] input.pdf [output.pdf] [pages] +.PP +The clean command pretty prints and rewrites the syntax of a PDF file. +It can be used to repair broken files, expand compressed streams, filter +out a range of pages, etc. +.PP +If no output file is specified, it will write the cleaned PDF to "out.pdf" +in the current directory. +.TP +.B \-p password +Use the specified password if the file is encrypted. +.TP +.B \-g +Garbage collect objects that have no references from other objects. +Give the option twice to renumber all objects and compact the cross reference table. +Give it three times to merge and reuse duplicate objects. +.TP +.B \-d +Decompress streams. This will make the output file larger, but provides +easy access for reading and editing the contents with a text editor. +.TP +.B pages +Comma separated list of page ranges to include. +.SH EXTRACT +TODO +.SH INFO +TODO +.SH POSTER +TODO +.SH SHOW +mubusy show [options] file.pdf [object numbers ...] +.PP +The show command will print the specified objects and streams to stdout. +Streams are decoded and non-printable characters are represented +with a period by default. +.TP +.B \-b +Print streams as binary data and omit the object header. +.TP +.B \-e +Print streams in their original encoded (or compressed) form. +.TP +.B \-p password +Use the specified password if the file is encrypted. +.PP +Specify objects by number, or use one of the following special names: +.TP +.B 'xref' or 'x' +Print the cross reference table. +.TP +.B 'trailer' or 't' +Print the trailer dictionary. +.TP +.B 'pages' or 'p' +List the object numbers for every page. +.TP +.B 'grep' or 'g' +Print all the objects in the file in a compact one-line format suitable for piping to grep. +.SH SEE ALSO +.BR mupdf (1), +.BR mudraw (1). +.SH AUTHOR +MuPDF is Copyright 2006-2012 Artifex Software, Inc. diff --git a/apps/man/mudraw.1 b/apps/man/mudraw.1 index 41bee152..cbe1b613 100644 --- a/apps/man/mudraw.1 +++ b/apps/man/mudraw.1 @@ -86,5 +86,4 @@ Comma separated list of ranges to render. .BR mupdfclean (1). .BR mupdfshow (1). .SH AUTHOR -MuPDF was written by Tor Andersson <tor@ghostscript.com>. MuPDF is Copyright 2006-2012 Artifex Software, Inc. diff --git a/apps/man/mupdf.1 b/apps/man/mupdf.1 index fc8e9640..dc2dfca1 100644 --- a/apps/man/mupdf.1 +++ b/apps/man/mupdf.1 @@ -86,7 +86,4 @@ Toggle between normal and inverted color rendering. .BR mupdfdraw (1), .BR mupdfshow (1). .SH AUTHOR -MuPDF was written by Tor Andersson <tor@ghostscript.com>. MuPDF is Copyright 2006-2012 Artifex Software, Inc. -.PP -This manual page was written by Sebastian Rasmussen <sebras@hotmail.com>. diff --git a/apps/man/mupdfclean.1 b/apps/man/mupdfclean.1 deleted file mode 100644 index 91e796ac..00000000 --- a/apps/man/mupdfclean.1 +++ /dev/null @@ -1,39 +0,0 @@ -.TH PDFCLEAN 1 "January 27, 2012" -.\" Please adjust this date whenever revising the manpage. -.SH NAME -mupdfclean \- pretty print, decompress and garbage collect PDF files -.SH SYNOPSIS -.B mupdfclean -.RI [ options ] -.RI input.pdf -.RI [ output.pdf ] -.RI [ pages ] -.SH DESCRIPTION -.B mupdfclean -pretty prints and rewrites the contents of a PDF file. -If no output file is specified, the new file will be written to "out.pdf" in -the current directory. -.PP -.SH OPTIONS -.TP -.B \-p password -Use the specified password if the file is encrypted. -.TP -.B \-g -Garbage collect objects that have no references from other objects. -Give the option twice to renumber all objects and compact the cross reference table. -Give it three times to merge and reuse duplicate objects. -.TP -.B \-d -Decompress streams. This will make the output file larger, but provides -easy access for reading and editing the contents with a text editor. -.TP -.B pages -Comma separated list of ranges to clean. -.SH SEE ALSO -.BR mupdf (1), -.BR mupdfdraw (1). -.BR mupdfshow (1). -.SH AUTHOR -MuPDF was written by Tor Andersson <tor@ghostscript.com>. -MuPDF is Copyright 2006-2010 Artifex Software, Inc. diff --git a/apps/man/mupdfshow.1 b/apps/man/mupdfshow.1 deleted file mode 100644 index 451dac6b..00000000 --- a/apps/man/mupdfshow.1 +++ /dev/null @@ -1,42 +0,0 @@ -.TH PDFSHOW 1 "January 27, 2012" -.\" Please adjust this date whenever revising the manpage. -.SH NAME -mupdfshow \- show objects and streams that make up a PDF document -.SH SYNOPSIS -.B mupdfshow -.RI [ options ] -.RI file.pdf -.RI [ xref ] -.RI [ trailer ] -.RI [ pages ] -.RI [ grep ] -.RI [ object-number... ] -.SH DESCRIPTION -.B mupdfshow -pretty prints the objects and streams specified on the command line. -Streams are decoded and non-printable characters are represented -with a period. -Specify objects with their number. -The special names xref, trailer and pages will -respectively print the cross reference, trailer, -and the object numbers for all pages. -The special name grep will print all objects in the file -in a compact one-line format suitable for piping to grep. -.PP -.SH OPTIONS -.TP -.B \-b -Print streams as binary data and omit the object header. -.TP -.B \-e -Print streams in their original encoded form. -.TP -.B \-p password -Use the specified password if the file is encrypted. -.SH SEE ALSO -.BR mupdf (1), -.BR mupdfclean (1). -.BR mupdfdraw (1). -.SH AUTHOR -MuPDF was written by Tor Andersson <tor@ghostscript.com>. -MuPDF is copyright 2006-2012 Artifex Software, Inc. diff --git a/apps/mubusy.c b/apps/mubusy.c index a9df26fa..b520d0ec 100644 --- a/apps/mubusy.c +++ b/apps/mubusy.c @@ -1,62 +1,83 @@ /* - * pdfbusy -- combined exe build + * mubusy -- swiss army knife of pdf manipulation tools */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + int pdfclean_main(int argc, char *argv[]); -int draw_main(int argc, char *argv[]); int pdfextract_main(int argc, char *argv[]); int pdfinfo_main(int argc, char *argv[]); +int pdfposter_main(int argc, char *argv[]); int pdfshow_main(int argc, char *argv[]); +static struct { + int (*func)(int argc, char *argv[]); + char *name; + char *desc; +} tools[] = { + { pdfclean_main, "clean", "rewrite pdf file" }, + { pdfextract_main, "extract", "extract font and image resources" }, + { pdfinfo_main, "info", "show information about pdf resources" }, + { pdfposter_main, "poster", "split large page into many tiles" }, + { pdfshow_main, "show", "show internal pdf objects" }, +}; + static int -namematch(const char *end, const char *start, const char *match, int len) +namematch(const char *end, const char *start, const char *match) { + int len = strlen(match); return ((end-len >= start) && (strncmp(end-len, match, len) == 0)); } int main(int argc, char **argv) { char *start, *end; + char buf[32]; + int i; + if (argc == 0) { fprintf(stderr, "No command name found!\n"); - exit(EXIT_FAILURE); + return 1; + } + + /* Check argv[0] */ + + if (argc > 0) + { + end = start = argv[0]; + while (*end) + end++; + if ((end-4 >= start) && (end[-4] == '.') && (end[-3] == 'e') && (end[-2] == 'x') && (end[-1] == 'e')) + end = end-4; + for (i = 0; i < nelem(tools); i++) + { + strcpy(buf, "mupdf"); + strcat(buf, tools[i].name); + if (namematch(end, start, buf)) + return tools[i].func(argc, argv); + } } - end = start = argv[0]; - while (*end) - end++; - if ((end-4 >= start) && (end[-4] == '.') && (end[-3] == 'e') && (end[-2] == 'x') && (end[-1] == 'e')) - end = end-4; - if (namematch(end, start, "mupdfdraw", 9) || namematch(end, start, "muxpsdraw", 9) || namematch(end, start, "mudraw", 6)) - return draw_main(argc, argv); - if (namematch(end, start, "mupdfclean", 10)) - return pdfclean_main(argc, argv); - if (namematch(end, start, "mupdfextract", 12)) - return pdfextract_main(argc, argv); - if (namematch(end, start, "mupdfshow", 9)) - return pdfshow_main(argc, argv); - if (namematch(end, start, "mupdfinfo", 9)) - return pdfinfo_main(argc, argv); - /* And include old names for backward compatibility */ - if (namematch(end, start, "pdfdraw", 7) || namematch(end, start, "xpsdraw", 7)) - return draw_main(argc, argv); - if (namematch(end, start, "pdfclean", 8)) - return pdfclean_main(argc, argv); - if (namematch(end, start, "pdfextract", 10)) - return pdfextract_main(argc, argv); - if (namematch(end, start, "pdfshow", 7)) - return pdfshow_main(argc, argv); - if (namematch(end, start, "pdfinfo", 7)) - return pdfinfo_main(argc, argv); - - fprintf(stderr, "mubusy: Combined build of mupdf/mudraw tools.\n\n"); - fprintf(stderr, "Invoke as one of the following:\n"); - fprintf(stderr, "\tmupdfclean, mudraw, mupdfextract, mupdfinfo, mupdfshow.\n"); - - return 0; + /* Check argv[1] */ + + if (argc > 1) + { + for (i = 0; i < nelem(tools); i++) + if (!strcmp(tools[i].name, argv[1])) + return tools[i].func(argc - 1, argv + 1); + } + + /* Print usage */ + + fprintf(stderr, "usage: mubusy <command> [options]\n"); + + for (i = 0; i < nelem(tools); i++) + fprintf(stderr, "\t%s\t-- %s\n", tools[i].name, tools[i].desc); + + return 1; } diff --git a/apps/mubusy_draw.c b/apps/mubusy_draw.c deleted file mode 100644 index 26b9bd6d..00000000 --- a/apps/mubusy_draw.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MUPDF_COMBINED_EXE -#include "mudraw.c" diff --git a/apps/mubusy_pdfclean.c b/apps/mubusy_pdfclean.c deleted file mode 100644 index bc3456d1..00000000 --- a/apps/mubusy_pdfclean.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MUPDF_COMBINED_EXE -#include "mupdfclean.c" diff --git a/apps/mubusy_pdfextract.c b/apps/mubusy_pdfextract.c deleted file mode 100644 index 30f661a3..00000000 --- a/apps/mubusy_pdfextract.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MUPDF_COMBINED_EXE -#include "mupdfextract.c" diff --git a/apps/mubusy_pdfinfo.c b/apps/mubusy_pdfinfo.c deleted file mode 100644 index df947543..00000000 --- a/apps/mubusy_pdfinfo.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MUPDF_COMBINED_EXE -#include "mupdfinfo.c" diff --git a/apps/mubusy_pdfshow.c b/apps/mubusy_pdfshow.c deleted file mode 100644 index 320b93aa..00000000 --- a/apps/mubusy_pdfshow.c +++ /dev/null @@ -1,2 +0,0 @@ -#define MUPDF_COMBINED_EXE -#include "mupdfshow.c" diff --git a/apps/mudraw.c b/apps/mudraw.c index 8abce8ed..6a90398f 100644 --- a/apps/mudraw.c +++ b/apps/mudraw.c @@ -34,11 +34,14 @@ static int fit = 0; static fz_text_sheet *sheet = NULL; static fz_colorspace *colorspace; static char *filename; +static int files = 0; static struct { int count, total; int min, max; int minpage, maxpage; + char *minfilename; + char *maxfilename; } timing; static void usage(void) @@ -348,11 +351,12 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) { timing.min = diff; timing.minpage = pagenum; + timing.minfilename = filename; } if (diff > timing.max) { timing.max = diff; - timing.maxpage = pagenum; + timing.maxfilename = filename; } timing.total += diff; timing.count ++; @@ -368,17 +372,17 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) static void drawrange(fz_context *ctx, fz_document *doc, char *range) { - int page, spage, epage, final; + int page, spage, epage, pagecount; char *spec, *dash; - final = fz_count_pages(doc); + pagecount = fz_count_pages(doc); spec = fz_strsep(&range, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) - spage = epage = final; + spage = epage = pagecount; else spage = epage = atoi(spec); @@ -387,11 +391,11 @@ static void drawrange(fz_context *ctx, fz_document *doc, char *range) if (strlen(dash) > 1) epage = atoi(dash + 1); else - epage = final; + epage = pagecount; } - spage = CLAMP(spage, 1, final); - epage = CLAMP(epage, 1, final); + spage = CLAMP(spage, 1, pagecount); + epage = CLAMP(epage, 1, pagecount); if (spage < epage) for (page = spage; page <= epage; page++) @@ -488,6 +492,8 @@ int main(int argc, char **argv) timing.max = 0; timing.minpage = 0; timing.maxpage = 0; + timing.minfilename = ""; + timing.maxfilename = ""; if (showxml || showtext == TEXT_XML) printf("<?xml version=\"1.0\"?>\n"); @@ -511,6 +517,7 @@ int main(int argc, char **argv) while (fz_optind < argc) { filename = argv[fz_optind++]; + files++; fz_try(ctx) { @@ -549,6 +556,7 @@ int main(int argc, char **argv) fz_catch(ctx) { fz_close_document(doc); + fprintf(stderr, "error: cannot draw '%s'\n", filename); } if (showtext == TEXT_HTML) @@ -562,12 +570,22 @@ int main(int argc, char **argv) if (showtext) fz_free_text_sheet(ctx, sheet); - if (showtime) + if (showtime && timing.count > 0) { - printf("total %dms / %d pages for an average of %dms\n", - timing.total, timing.count, timing.total / timing.count); - printf("fastest page %d: %dms\n", timing.minpage, timing.min); - printf("slowest page %d: %dms\n", timing.maxpage, timing.max); + if (files == 1) + { + printf("total %dms / %d pages for an average of %dms\n", + timing.total, timing.count, timing.total / timing.count); + printf("fastest page %d: %dms\n", timing.minpage, timing.min); + printf("slowest page %d: %dms\n", timing.maxpage, timing.max); + } + else + { + printf("total %dms / %d pages for an average of %dms in %d files\n", + timing.total, timing.count, timing.total / timing.count, files); + printf("fastest page %d: %dms (%s)\n", timing.minpage, timing.min, timing.minfilename); + printf("slowest page %d: %dms (%s)\n", timing.maxpage, timing.max, timing.maxfilename); + } } fz_free_context(ctx); diff --git a/apps/mupdfclean.c b/apps/mupdfclean.c index 5b95fdae..ad210bdb 100644 --- a/apps/mupdfclean.c +++ b/apps/mupdfclean.c @@ -12,31 +12,13 @@ #include "fitz.h" #include "mupdf-internal.h" -static FILE *out = NULL; - -enum -{ - expand_images = 1, - expand_fonts = 2, - expand_all = -1 -}; - -static char *uselist = NULL; -static int *ofslist = NULL; -static int *genlist = NULL; -static int *renumbermap = NULL; - -static int dogarbage = 0; -static int doexpand = 0; -static int doascii = 0; - static pdf_document *xref = NULL; static fz_context *ctx = NULL; static void usage(void) { fprintf(stderr, - "usage: pdfclean [options] input.pdf [output.pdf] [pages]\n" + "usage: mubusy clean [options] input.pdf [output.pdf] [pages]\n" "\t-p -\tpassword\n" "\t-g\tgarbage collect unused objects\n" "\t-gg\tin addition to -g compact xref table\n" @@ -50,251 +32,6 @@ static void usage(void) } /* - * Garbage collect objects not reachable from the trailer. - */ - -static pdf_obj *sweepref(pdf_obj *obj) -{ - int num = pdf_to_num(obj); - int gen = pdf_to_gen(obj); - - if (num < 0 || num >= xref->len) - return NULL; - if (uselist[num]) - return NULL; - - uselist[num] = 1; - - /* Bake in /Length in stream objects */ - fz_try(ctx) - { - if (pdf_is_stream(xref, num, gen)) - { - pdf_obj *len = pdf_dict_gets(obj, "Length"); - if (pdf_is_indirect(len)) - { - uselist[pdf_to_num(len)] = 0; - len = pdf_resolve_indirect(len); - pdf_dict_puts(obj, "Length", len); - } - } - } - fz_catch(ctx) - { - /* Leave broken */ - } - - return pdf_resolve_indirect(obj); -} - -static void sweepobj(pdf_obj *obj) -{ - int i; - - if (pdf_is_indirect(obj)) - obj = sweepref(obj); - - if (pdf_is_dict(obj)) - { - int n = pdf_dict_len(obj); - for (i = 0; i < n; i++) - sweepobj(pdf_dict_get_val(obj, i)); - } - - else if (pdf_is_array(obj)) - { - int n = pdf_array_len(obj); - for (i = 0; i < n; i++) - sweepobj(pdf_array_get(obj, i)); - } -} - -/* - * Scan for and remove duplicate objects (slow) - */ - -static void removeduplicateobjs(void) -{ - int num, other; - - for (num = 1; num < xref->len; num++) - { - /* Only compare an object to objects preceding it */ - for (other = 1; other < num; other++) - { - pdf_obj *a, *b; - - if (num == other || !uselist[num] || !uselist[other]) - continue; - - /* - * Comparing stream objects data contents would take too long. - * - * pdf_is_stream calls pdf_cache_object and ensures - * that the xref table has the objects loaded. - */ - fz_try(ctx) - { - if (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0)) - continue; - } - fz_catch(ctx) - { - /* Assume different */ - } - - a = xref->table[num].obj; - b = xref->table[other].obj; - - a = pdf_resolve_indirect(a); - b = pdf_resolve_indirect(b); - - if (pdf_objcmp(a, b)) - continue; - - /* Keep the lowest numbered object */ - renumbermap[num] = MIN(num, other); - renumbermap[other] = MIN(num, other); - uselist[MAX(num, other)] = 0; - - /* One duplicate was found, do not look for another */ - break; - } - } -} - -/* - * Renumber objects sequentially so the xref is more compact - */ - -static void compactxref(void) -{ - int num, newnum; - - /* - * Update renumbermap in-place, clustering all used - * objects together at low object ids. Objects that - * already should be renumbered will have their new - * object ids be updated to reflect the compaction. - */ - - newnum = 1; - for (num = 1; num < xref->len; num++) - { - if (uselist[num] && renumbermap[num] == num) - renumbermap[num] = newnum++; - else if (renumbermap[num] != num) - renumbermap[num] = renumbermap[renumbermap[num]]; - } -} - -/* - * Update indirect objects according to renumbering established when - * removing duplicate objects and compacting the xref. - */ - -static void renumberobj(pdf_obj *obj) -{ - int i; - fz_context *ctx = xref->ctx; - - if (pdf_is_dict(obj)) - { - int n = pdf_dict_len(obj); - for (i = 0; i < n; i++) - { - pdf_obj *key = pdf_dict_get_key(obj, i); - pdf_obj *val = pdf_dict_get_val(obj, i); - if (pdf_is_indirect(val)) - { - val = pdf_new_indirect(ctx, renumbermap[pdf_to_num(val)], 0, xref); - fz_dict_put(obj, key, val); - pdf_drop_obj(val); - } - else - { - renumberobj(val); - } - } - } - - else if (pdf_is_array(obj)) - { - int n = pdf_array_len(obj); - for (i = 0; i < n; i++) - { - pdf_obj *val = pdf_array_get(obj, i); - if (pdf_is_indirect(val)) - { - val = pdf_new_indirect(ctx, renumbermap[pdf_to_num(val)], 0, xref); - pdf_array_put(obj, i, val); - pdf_drop_obj(val); - } - else - { - renumberobj(val); - } - } - } -} - -static void renumberobjs(void) -{ - pdf_xref_entry *oldxref; - int newlen; - int num; - - /* Apply renumber map to indirect references in all objects in xref */ - renumberobj(xref->trailer); - for (num = 0; num < xref->len; num++) - { - pdf_obj *obj = xref->table[num].obj; - - if (pdf_is_indirect(obj)) - { - obj = pdf_new_indirect(ctx, renumbermap[pdf_to_num(obj)], 0, xref); - pdf_update_object(xref, num, 0, obj); - pdf_drop_obj(obj); - } - else - { - renumberobj(obj); - } - } - - /* Create new table for the reordered, compacted xref */ - oldxref = xref->table; - xref->table = fz_malloc_array(xref->ctx, xref->len, sizeof(pdf_xref_entry)); - xref->table[0] = oldxref[0]; - - /* Move used objects into the new compacted xref */ - newlen = 0; - for (num = 1; num < xref->len; num++) - { - if (uselist[num]) - { - if (newlen < renumbermap[num]) - newlen = renumbermap[num]; - xref->table[renumbermap[num]] = oldxref[num]; - } - else - { - if (oldxref[num].obj) - pdf_drop_obj(oldxref[num].obj); - } - } - - fz_free(xref->ctx, oldxref); - - /* Update the used objects count in compacted xref */ - xref->len = newlen + 1; - - /* Update list of used objects to fit with compacted xref */ - for (num = 1; num < xref->len; num++) - uselist[num] = 1; -} - -/* * Recreate page tree to only retain specified pages. */ @@ -312,7 +49,7 @@ static void retainpages(int argc, char **argv) pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); - pdf_update_object(xref, pdf_to_num(oldroot), pdf_to_gen(oldroot), root); + pdf_update_object(xref, pdf_to_num(oldroot), root); pdf_drop_obj(root); @@ -323,17 +60,18 @@ static void retainpages(int argc, char **argv) /* Retain pages specified */ while (argc - fz_optind) { - int page, spage, epage; + int page, spage, epage, pagecount; char *spec, *dash; char *pagelist = argv[fz_optind]; + pagecount = pdf_count_pages(xref); spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) - spage = epage = pdf_count_pages(xref); + spage = epage = pagecount; else spage = epage = atoi(spec); @@ -342,16 +80,14 @@ static void retainpages(int argc, char **argv) if (strlen(dash) > 1) epage = atoi(dash + 1); else - epage = pdf_count_pages(xref); + epage = pagecount; } if (spage > epage) page = spage, spage = epage, epage = page; - if (spage < 1) - spage = 1; - if (epage > pdf_count_pages(xref)) - epage = pdf_count_pages(xref); + spage = CLAMP(spage, 1, pagecount); + epage = CLAMP(epage, 1, pagecount); for (page = spage; page <= epage; page++) { @@ -415,352 +151,29 @@ static void retainpages(int argc, char **argv) } } -/* - * Make sure we have loaded objects from object streams. - */ - -static void preloadobjstms(void) -{ - pdf_obj *obj; - int num; - - for (num = 0; num < xref->len; num++) - { - if (xref->table[num].type == 'o') - { - obj = pdf_load_object(xref, num, 0); - pdf_drop_obj(obj); - } - } -} - -/* - * Save streams and objects to the output - */ - -static inline int isbinary(int c) -{ - if (c == '\n' || c == '\r' || c == '\t') - return 0; - return c < 32 || c > 127; -} - -static int isbinarystream(fz_buffer *buf) -{ - int i; - for (i = 0; i < buf->len; i++) - if (isbinary(buf->data[i])) - return 1; - return 0; -} - -static fz_buffer *hexbuf(unsigned char *p, int n) -{ - static const char hex[16] = "0123456789abcdef"; - fz_buffer *buf; - int x = 0; - - buf = fz_new_buffer(ctx, n * 2 + (n / 32) + 2); - - while (n--) - { - buf->data[buf->len++] = hex[*p >> 4]; - buf->data[buf->len++] = hex[*p & 15]; - if (++x == 32) - { - buf->data[buf->len++] = '\n'; - x = 0; - } - p++; - } - - buf->data[buf->len++] = '>'; - buf->data[buf->len++] = '\n'; - - return buf; -} - -static void addhexfilter(pdf_obj *dict) -{ - pdf_obj *f, *dp, *newf, *newdp; - pdf_obj *ahx, *nullobj; - - ahx = fz_new_name(ctx, "ASCIIHexDecode"); - nullobj = pdf_new_null(ctx); - newf = newdp = NULL; - - f = pdf_dict_gets(dict, "Filter"); - dp = pdf_dict_gets(dict, "DecodeParms"); - - if (pdf_is_name(f)) - { - newf = pdf_new_array(ctx, 2); - pdf_array_push(newf, ahx); - pdf_array_push(newf, f); - f = newf; - if (pdf_is_dict(dp)) - { - newdp = pdf_new_array(ctx, 2); - pdf_array_push(newdp, nullobj); - pdf_array_push(newdp, dp); - dp = newdp; - } - } - else if (pdf_is_array(f)) - { - pdf_array_insert(f, ahx); - if (pdf_is_array(dp)) - pdf_array_insert(dp, nullobj); - } - else - f = ahx; - - pdf_dict_puts(dict, "Filter", f); - if (dp) - pdf_dict_puts(dict, "DecodeParms", dp); - - pdf_drop_obj(ahx); - pdf_drop_obj(nullobj); - if (newf) - pdf_drop_obj(newf); - if (newdp) - pdf_drop_obj(newdp); -} - -static void copystream(pdf_obj *obj, int num, int gen) -{ - fz_buffer *buf, *tmp; - pdf_obj *newlen; - - buf = pdf_load_raw_stream(xref, num, gen); - - if (doascii && isbinarystream(buf)) - { - tmp = hexbuf(buf->data, buf->len); - fz_drop_buffer(ctx, buf); - buf = tmp; - - addhexfilter(obj); - - newlen = pdf_new_int(ctx, buf->len); - pdf_dict_puts(obj, "Length", newlen); - pdf_drop_obj(newlen); - } - - fprintf(out, "%d %d obj\n", num, gen); - pdf_fprint_obj(out, obj, doexpand == 0); - fprintf(out, "stream\n"); - fwrite(buf->data, 1, buf->len, out); - fprintf(out, "endstream\nendobj\n\n"); - - fz_drop_buffer(ctx, buf); -} - -static void expandstream(pdf_obj *obj, int num, int gen) -{ - fz_buffer *buf, *tmp; - pdf_obj *newlen; - - buf = pdf_load_stream(xref, num, gen); - - pdf_dict_dels(obj, "Filter"); - pdf_dict_dels(obj, "DecodeParms"); - - if (doascii && isbinarystream(buf)) - { - tmp = hexbuf(buf->data, buf->len); - fz_drop_buffer(ctx, buf); - buf = tmp; - - addhexfilter(obj); - } - - newlen = pdf_new_int(ctx, buf->len); - pdf_dict_puts(obj, "Length", newlen); - pdf_drop_obj(newlen); - - fprintf(out, "%d %d obj\n", num, gen); - pdf_fprint_obj(out, obj, doexpand == 0); - fprintf(out, "stream\n"); - fwrite(buf->data, 1, buf->len, out); - fprintf(out, "endstream\nendobj\n\n"); - - fz_drop_buffer(ctx, buf); -} - -static void writeobject(int num, int gen) -{ - pdf_obj *obj; - pdf_obj *type; - - obj = pdf_load_object(xref, num, gen); - - /* skip ObjStm and XRef objects */ - if (pdf_is_dict(obj)) - { - type = pdf_dict_gets(obj, "Type"); - if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "ObjStm")) - { - uselist[num] = 0; - pdf_drop_obj(obj); - return; - } - if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "XRef")) - { - uselist[num] = 0; - pdf_drop_obj(obj); - return; - } - } - - if (!pdf_is_stream(xref, num, gen)) - { - fprintf(out, "%d %d obj\n", num, gen); - pdf_fprint_obj(out, obj, doexpand == 0); - fprintf(out, "endobj\n\n"); - } - else - { - int dontexpand = 0; - if (doexpand != 0 && doexpand != expand_all) - { - pdf_obj *o; - - if ((o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "XObject")) && - (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Image"))) - dontexpand = !(doexpand & expand_images); - if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "Font")) - dontexpand = !(doexpand & expand_fonts); - if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "FontDescriptor")) - dontexpand = !(doexpand & expand_fonts); - if ((o = pdf_dict_gets(obj, "Length1")) != NULL) - dontexpand = !(doexpand & expand_fonts); - if ((o = pdf_dict_gets(obj, "Length2")) != NULL) - dontexpand = !(doexpand & expand_fonts); - if ((o = pdf_dict_gets(obj, "Length3")) != NULL) - dontexpand = !(doexpand & expand_fonts); - if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Type1C")) - dontexpand = !(doexpand & expand_fonts); - if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "CIDFontType0C")) - dontexpand = !(doexpand & expand_fonts); - } - if (doexpand && !dontexpand && !pdf_is_jpx_image(ctx, obj)) - expandstream(obj, num, gen); - else - copystream(obj, num, gen); - } - - pdf_drop_obj(obj); -} - -static void writexref(void) -{ - pdf_obj *trailer; - pdf_obj *obj; - int startxref; - int num; - - startxref = ftell(out); - - fprintf(out, "xref\n0 %d\n", xref->len); - for (num = 0; num < xref->len; num++) - { - if (uselist[num]) - fprintf(out, "%010d %05d n \n", ofslist[num], genlist[num]); - else - fprintf(out, "%010d %05d f \n", ofslist[num], genlist[num]); - } - fprintf(out, "\n"); - - trailer = pdf_new_dict(ctx, 5); - - obj = pdf_new_int(ctx, xref->len); - pdf_dict_puts(trailer, "Size", obj); - pdf_drop_obj(obj); - - obj = pdf_dict_gets(xref->trailer, "Info"); - if (obj) - pdf_dict_puts(trailer, "Info", obj); - - obj = pdf_dict_gets(xref->trailer, "Root"); - if (obj) - pdf_dict_puts(trailer, "Root", obj); - - obj = pdf_dict_gets(xref->trailer, "ID"); - if (obj) - pdf_dict_puts(trailer, "ID", obj); - - fprintf(out, "trailer\n"); - pdf_fprint_obj(out, trailer, doexpand == 0); - fprintf(out, "\n"); - - pdf_drop_obj(trailer); - - fprintf(out, "startxref\n%d\n%%%%EOF\n", startxref); -} - -static void writepdf(void) -{ - int lastfree; - int num; - - for (num = 0; num < xref->len; num++) - { - if (xref->table[num].type == 'f') - genlist[num] = xref->table[num].gen; - if (xref->table[num].type == 'n') - genlist[num] = xref->table[num].gen; - if (xref->table[num].type == 'o') - genlist[num] = 0; - - if (dogarbage && !uselist[num]) - continue; - - if (xref->table[num].type == 'n' || xref->table[num].type == 'o') - { - uselist[num] = 1; - ofslist[num] = ftell(out); - writeobject(num, genlist[num]); - } - } - - /* Construct linked list of free object slots */ - lastfree = 0; - for (num = 0; num < xref->len; num++) - { - if (!uselist[num]) - { - genlist[num]++; - ofslist[lastfree] = num; - lastfree = num; - } - } - - writexref(); -} - -#ifdef MUPDF_COMBINED_EXE int pdfclean_main(int argc, char **argv) -#else -int main(int argc, char **argv) -#endif { char *infile; char *outfile = "out.pdf"; char *password = ""; - int c, num; + int c; int subset; + fz_write_options opts; + + opts.dogarbage = 0; + opts.doexpand = 0; + opts.doascii = 0; while ((c = fz_getopt(argc, argv, "adfgip:")) != -1) { switch (c) { case 'p': password = fz_optarg; break; - case 'g': dogarbage ++; break; - case 'd': doexpand ^= expand_all; break; - case 'f': doexpand ^= expand_fonts; break; - case 'i': doexpand ^= expand_images; break; - case 'a': doascii ++; break; + case 'g': opts.dogarbage ++; break; + case 'd': opts.doexpand ^= fz_expand_all; break; + case 'f': opts.doexpand ^= fz_expand_fonts; break; + case 'i': opts.doexpand ^= fz_expand_images; break; + case 'a': opts.doascii ++; break; default: usage(); break; } } @@ -787,66 +200,16 @@ int main(int argc, char **argv) exit(1); } - xref = pdf_open_document(ctx, infile); + xref = pdf_open_document_no_run(ctx, infile); if (pdf_needs_password(xref)) if (!pdf_authenticate_password(xref, password)) fz_throw(ctx, "cannot authenticate password: %s", infile); - out = fopen(outfile, "wb"); - if (!out) - fz_throw(ctx, "cannot open output file '%s'", outfile); - - fprintf(out, "%%PDF-%d.%d\n", xref->version / 10, xref->version % 10); - fprintf(out, "%%\316\274\341\277\246\n\n"); - - uselist = fz_malloc_array(ctx, xref->len + 1, sizeof(char)); - ofslist = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); - genlist = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); - renumbermap = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); - - for (num = 0; num < xref->len; num++) - { - uselist[num] = 0; - ofslist[num] = 0; - genlist[num] = 0; - renumbermap[num] = num; - } - - /* Make sure any objects hidden in compressed streams have been loaded */ - preloadobjstms(); - /* Only retain the specified subset of the pages */ if (subset) retainpages(argc, argv); - /* Sweep & mark objects from the trailer */ - if (dogarbage >= 1) - sweepobj(xref->trailer); - - /* Coalesce and renumber duplicate objects */ - if (dogarbage >= 3) - removeduplicateobjs(); - - /* Compact xref by renumbering and removing unused objects */ - if (dogarbage >= 2) - compactxref(); - - /* 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 (dogarbage >= 2 && !xref->crypt) - renumberobjs(); - - writepdf(); - - if (fclose(out)) - fz_throw(ctx, "cannot close output file '%s'", outfile); - - fz_free(xref->ctx, uselist); - fz_free(xref->ctx, ofslist); - fz_free(xref->ctx, genlist); - fz_free(xref->ctx, renumbermap); + pdf_write_document(xref, outfile, &opts); pdf_close_document(xref); fz_free_context(ctx); diff --git a/apps/mupdfextract.c b/apps/mupdfextract.c index a6a677cd..8db6ceaf 100644 --- a/apps/mupdfextract.c +++ b/apps/mupdfextract.c @@ -3,6 +3,7 @@ */ #include "mupdf.h" +#include "mupdf-internal.h" static pdf_document *doc = NULL; static fz_context *ctx = NULL; @@ -10,7 +11,7 @@ static int dorgb = 0; static void usage(void) { - fprintf(stderr, "usage: pdfextract [options] file.pdf [object numbers]\n"); + fprintf(stderr, "usage: mubusy extract [options] file.pdf [object numbers]\n"); fprintf(stderr, "\t-p\tpassword\n"); fprintf(stderr, "\t-r\tconvert images to rgb\n"); exit(1); @@ -142,11 +143,7 @@ static void showobject(int num) pdf_drop_obj(obj); } -#ifdef MUPDF_COMBINED_EXE int pdfextract_main(int argc, char **argv) -#else -int main(int argc, char **argv) -#endif { char *infile; char *password = ""; @@ -174,7 +171,7 @@ int main(int argc, char **argv) exit(1); } - doc = pdf_open_document(ctx, infile); + doc = pdf_open_document_no_run(ctx, infile); if (pdf_needs_password(doc)) if (!pdf_authenticate_password(doc, password)) fz_throw(ctx, "cannot authenticate password: %s", infile); diff --git a/apps/mupdfinfo.c b/apps/mupdfinfo.c index ace390a6..6e4db812 100644 --- a/apps/mupdfinfo.c +++ b/apps/mupdfinfo.c @@ -154,7 +154,7 @@ static void infousage(void) { fprintf(stderr, - "usage: pdfinfo [options] [file.pdf ... ]\n" + "usage: mubusy info [options] [file.pdf ... ]\n" "\t-d -\tpassword for decryption\n" "\t-f\tlist fonts\n" "\t-i\tlist images\n" @@ -552,7 +552,7 @@ gatherpatterns(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) } static void -gatherresourceinfo(int page, pdf_obj *rsrc) +gatherresourceinfo(int page, pdf_obj *rsrc, int show) { pdf_obj *pageobj; pdf_obj *pageref; @@ -570,7 +570,7 @@ gatherresourceinfo(int page, pdf_obj *rsrc) fz_throw(ctx, "cannot retrieve info from page %d", page); font = pdf_dict_gets(rsrc, "Font"); - if (font) + if (show & FONTS && font) { int n; @@ -582,12 +582,12 @@ gatherresourceinfo(int page, pdf_obj *rsrc) subrsrc = pdf_dict_gets(obj, "Resources"); if (subrsrc && pdf_objcmp(rsrc, subrsrc)) - gatherresourceinfo(page, subrsrc); + gatherresourceinfo(page, subrsrc, show); } } xobj = pdf_dict_gets(rsrc, "XObject"); - if (xobj) + if (show & XOBJS && xobj) { int n; @@ -600,16 +600,16 @@ gatherresourceinfo(int page, pdf_obj *rsrc) pdf_obj *obj = pdf_dict_get_val(xobj, i); subrsrc = pdf_dict_gets(obj, "Resources"); if (subrsrc && pdf_objcmp(rsrc, subrsrc)) - gatherresourceinfo(page, subrsrc); + gatherresourceinfo(page, subrsrc, show); } } shade = pdf_dict_gets(rsrc, "Shading"); - if (shade) + if (show & SHADINGS && shade) gathershadings(page, pageref, pageobj, shade); pattern = pdf_dict_gets(rsrc, "Pattern"); - if (pattern) + if (show & PATTERNS && pattern) { int n; gatherpatterns(page, pageref, pageobj, pattern); @@ -619,13 +619,13 @@ gatherresourceinfo(int page, pdf_obj *rsrc) pdf_obj *obj = pdf_dict_get_val(pattern, i); subrsrc = pdf_dict_gets(obj, "Resources"); if (subrsrc && pdf_objcmp(rsrc, subrsrc)) - gatherresourceinfo(page, subrsrc); + gatherresourceinfo(page, subrsrc, show); } } } static void -gatherpageinfo(int page) +gatherpageinfo(int page, int show) { pdf_obj *pageobj; pdf_obj *pageref; @@ -640,7 +640,7 @@ gatherpageinfo(int page) gatherdimensions(page, pageref, pageobj); rsrc = pdf_dict_gets(pageobj, "Resources"); - gatherresourceinfo(page, rsrc); + gatherresourceinfo(page, rsrc, show); } static void @@ -882,12 +882,14 @@ showinfo(char *filename, int show, char *pagelist) int page, spage, epage; char *spec, *dash; int allpages; + int pagecount; if (!xref) infousage(); allpages = !strcmp(pagelist, "1-"); + pagecount = pdf_count_pages(xref); spec = fz_strsep(&pagelist, ","); while (spec) { @@ -909,26 +911,19 @@ showinfo(char *filename, int show, char *pagelist) if (spage > epage) page = spage, spage = epage, epage = page; - if (spage < 1) - spage = 1; - if (epage > pagecount) - epage = pagecount; - if (spage > pagecount) - spage = pagecount; + spage = CLAMP(spage, 1, pagecount); + epage = CLAMP(epage, 1, pagecount); if (allpages) printf("Retrieving info from pages %d-%d...\n", spage, epage); - if (spage >= 1) + for (page = spage; page <= epage; page++) { - for (page = spage; page <= epage; page++) + gatherpageinfo(page, show); + if (!allpages) { - gatherpageinfo(page); - if (!allpages) - { - printf("Page %d:\n", page); - printinfo(filename, show, page); - printf("\n"); - } + printf("Page %d:\n", page); + printinfo(filename, show, page); + printf("\n"); } } @@ -951,11 +946,7 @@ static int arg_is_page_range(const char *arg) return 1; } -#ifdef MUPDF_COMBINED_EXE int pdfinfo_main(int argc, char **argv) -#else -int main(int argc, char **argv) -#endif { enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state; char *filename = ""; @@ -1005,7 +996,7 @@ int main(int argc, char **argv) filename = argv[fz_optind]; printf("%s:\n", filename); - xref = pdf_open_document(ctx, filename); + xref = pdf_open_document_no_run(ctx, filename); if (pdf_needs_password(xref)) if (!pdf_authenticate_password(xref, password)) fz_throw(ctx, "cannot authenticate password: %s", filename); diff --git a/apps/mupdfposter.c b/apps/mupdfposter.c new file mode 100644 index 00000000..317c2c5d --- /dev/null +++ b/apps/mupdfposter.c @@ -0,0 +1,184 @@ +/* + * PDF cleaning tool: general purpose pdf syntax washer. + * + * Rewrite PDF with pretty printed objects. + * Garbage collect unreachable objects. + * Inflate compressed streams. + * Create subset documents. + * + * TODO: linearize document for fast web view + */ + +#include "fitz.h" +#include "mupdf-internal.h" + +static int x_factor = 0; +static int y_factor = 0; + +static void usage(void) +{ + fprintf(stderr, + "usage: mubusy poster [options] input.pdf [output.pdf]\n" + "\t-p -\tpassword\n" + "\t-x\tx decimation factor\n" + "\t-y\ty decimation factor\n"); + exit(1); +} + +/* + * Recreate page tree to only retain specified pages. + */ + +static void decimatepages(pdf_document *xref) +{ + pdf_obj *oldroot, *root, *pages, *kids, *parent; + fz_context *ctx = xref->ctx; + int num_pages = pdf_count_pages(xref); + int page, kidcount; + + /* Keep only pages/type and (reduced) dest entries to avoid + * references to unretained pages */ + oldroot = pdf_dict_gets(xref->trailer, "Root"); + pages = pdf_dict_gets(oldroot, "Pages"); + + root = pdf_new_dict(ctx, 2); + pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); + pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); + + pdf_update_object(xref, pdf_to_num(oldroot), root); + + pdf_drop_obj(root); + + /* Create a new kids array with only the pages we want to keep */ + parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); + kids = pdf_new_array(ctx, 1); + + kidcount = 0; + for (page=0; page < num_pages; page++) + { + pdf_page *page_details = pdf_load_page(xref, page); + int xf = x_factor, yf = y_factor; + int x, y; + float w = page_details->mediabox.x1 - page_details->mediabox.x0; + float h = page_details->mediabox.y1 - page_details->mediabox.y0; + + if (xf == 0 && yf == 0) + { + /* Nothing specified, so split along the long edge */ + if (w > h) + xf = 2, yf = 1; + else + xf = 1, yf = 2; + } + else if (xf == 0) + xf = 1; + else if (yf == 0) + yf = 1; + + for (y = yf-1; y >= 0; y--) + { + for (x = 0; x < xf; x++) + { + pdf_obj *newpageobj, *newpageref, *newmediabox; + fz_rect mb; + int num; + + newpageobj = pdf_copy_dict(ctx, xref->page_objs[page]); + num = pdf_create_object(xref); + pdf_update_object(xref, num, newpageobj); + newpageref = pdf_new_indirect(ctx, num, 0, xref); + + newmediabox = pdf_new_array(ctx, 4); + + mb.x0 = page_details->mediabox.x0 + (w/xf)*x; + if (x == xf-1) + mb.x1 = page_details->mediabox.x1; + else + mb.x1 = page_details->mediabox.x0 + (w/xf)*(x+1); + mb.y0 = page_details->mediabox.y0 + (h/yf)*y; + if (y == yf-1) + mb.y1 = page_details->mediabox.y1; + else + mb.y1 = page_details->mediabox.y0 + (h/yf)*(y+1); + + pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x0)); + pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y0)); + pdf_array_push(newmediabox, pdf_new_real(ctx, mb.x1)); + pdf_array_push(newmediabox, pdf_new_real(ctx, mb.y1)); + + pdf_dict_puts(newpageobj, "Parent", parent); + pdf_dict_puts(newpageobj, "MediaBox", newmediabox); + + /* Store page object in new kids array */ + pdf_array_push(kids, newpageref); + + kidcount++; + } + } + } + + pdf_drop_obj(parent); + + /* Update page count and kids array */ + pdf_dict_puts(pages, "Count", pdf_new_int(ctx, kidcount)); + pdf_dict_puts(pages, "Kids", kids); + pdf_drop_obj(kids); +} + +int pdfposter_main(int argc, char **argv) +{ + char *infile; + char *outfile = "out.pdf"; + char *password = ""; + int c; + fz_write_options opts; + pdf_document *xref; + fz_context *ctx; + + opts.dogarbage = 0; + opts.doexpand = 0; + opts.doascii = 0; + + while ((c = fz_getopt(argc, argv, "x:y:")) != -1) + { + switch (c) + { + case 'p': password = fz_optarg; break; + case 'x': x_factor = atoi(fz_optarg); break; + case 'y': y_factor = atoi(fz_optarg); break; + default: usage(); break; + } + } + + if (argc - fz_optind < 1) + usage(); + + infile = argv[fz_optind++]; + + if (argc - fz_optind > 0 && + (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))) + { + outfile = argv[fz_optind++]; + } + + ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + if (!ctx) + { + fprintf(stderr, "cannot initialise context\n"); + exit(1); + } + + xref = pdf_open_document_no_run(ctx, infile); + if (pdf_needs_password(xref)) + if (!pdf_authenticate_password(xref, password)) + fz_throw(ctx, "cannot authenticate password: %s", infile); + + /* Only retain the specified subset of the pages */ + decimatepages(xref); + + pdf_write_document(xref, outfile, &opts); + + pdf_close_document(xref); + fz_free_context(ctx); + return 0; +} diff --git a/apps/mupdfshow.c b/apps/mupdfshow.c index 70ca7a62..252e7dc2 100644 --- a/apps/mupdfshow.c +++ b/apps/mupdfshow.c @@ -12,7 +12,7 @@ static int showcolumn; static void usage(void) { - fprintf(stderr, "usage: pdfshow [options] file.pdf [grepable] [xref] [trailer] [pagetree] [object numbers]\n"); + fprintf(stderr, "usage: mubusy show [options] file.pdf [grepable] [xref] [trailer] [pagetree] [object numbers]\n"); fprintf(stderr, "\t-b\tprint streams as binary data\n"); fprintf(stderr, "\t-e\tprint encoded streams (don't decode)\n"); fprintf(stderr, "\t-p\tpassword\n"); @@ -171,11 +171,7 @@ static void showgrep(char *filename) pdf_fprint_obj(stdout, doc->trailer, 1); } -#ifdef MUPDF_COMBINED_EXE int pdfshow_main(int argc, char **argv) -#else -int main(int argc, char **argv) -#endif { char *password = NULL; /* don't throw errors if encrypted */ char *filename; @@ -207,10 +203,10 @@ int main(int argc, char **argv) fz_var(doc); fz_try(ctx) { - doc = pdf_open_document(ctx, filename); + doc = pdf_open_document_no_run(ctx, filename); if (pdf_needs_password(doc)) if (!pdf_authenticate_password(doc, password)) - fz_throw(ctx, "cannot authenticate password: %s", filename); + fz_warn(ctx, "cannot authenticate password: %s", filename); if (fz_optind == argc) showtrailer(); diff --git a/apps/pdfapp.c b/apps/pdfapp.c index eb39c6fa..b5b28867 100644 --- a/apps/pdfapp.c +++ b/apps/pdfapp.c @@ -227,7 +227,10 @@ static void pdfapp_panview(pdfapp_t *app, int newx, int newy) static void pdfapp_loadpage(pdfapp_t *app) { - fz_device *mdev; + fz_device *mdev = NULL; + int errored = 0; + + fz_var(mdev); if (app->page_list) fz_free_display_list(app->ctx, app->page_list); @@ -245,23 +248,48 @@ static void pdfapp_loadpage(pdfapp_t *app) app->page_sheet = NULL; app->page_links = NULL; app->page = NULL; + app->page_bbox.x0 = 0; + app->page_bbox.y0 = 0; + app->page_bbox.x1 = 100; + app->page_bbox.y1 = 100; fz_try(app->ctx) { app->page = fz_load_page(app->doc, app->pageno - 1); + app->page_bbox = fz_bound_page(app->doc, app->page); + } + fz_catch(app->ctx) + { + pdfapp_warn(app, "Cannot load page"); + return; + } + + fz_try(app->ctx) + { /* Create display list */ app->page_list = fz_new_display_list(app->ctx); mdev = fz_new_list_device(app->ctx, app->page_list); fz_run_page(app->doc, app->page, mdev, fz_identity, NULL); + } + fz_always(app->ctx) + { fz_free_device(mdev); + } + fz_catch(app->ctx) + { + pdfapp_warn(app, "Cannot load page"); + errored = 1; + } - app->page_bbox = fz_bound_page(app->doc, app->page); + fz_try(app->ctx) + { app->page_links = fz_load_links(app->doc, app->page); } fz_catch(app->ctx) { - pdfapp_error(app, "cannot load page"); + if (!errored) + pdfapp_warn(app, "Cannot load page"); } } diff --git a/apps/x11_main.c b/apps/x11_main.c index 6ab5b43a..941afcfa 100644 --- a/apps/x11_main.c +++ b/apps/x11_main.c @@ -59,6 +59,7 @@ extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty, int srcx, int srcy, int srcw, int srch, int srcstride); void windrawstringxor(pdfapp_t *app, int x, int y, char *s); +void cleanup(pdfapp_t *app); static Display *xdpy; static Atom XA_TARGETS; @@ -100,6 +101,7 @@ static int showingpage = 0; void winerror(pdfapp_t *app, char *msg) { fprintf(stderr, "mupdf: error: %s\n", msg); + cleanup(app); exit(1); } @@ -215,6 +217,27 @@ void winclose(pdfapp_t *app) closing = 1; } +void cleanup(pdfapp_t *app) +{ + fz_context *ctx = app->ctx; + + pdfapp_close(app); + + XDestroyWindow(xdpy, xwin); + + XFreePixmap(xdpy, xicon); + + XFreeCursor(xdpy, xcwait); + XFreeCursor(xdpy, xchand); + XFreeCursor(xdpy, xcarrow); + + XFreeGC(xdpy, xgc); + + XCloseDisplay(xdpy); + + fz_free_context(ctx); +} + static int winresolution() { return DisplayWidth(xdpy, xscr) * 25.4 / @@ -825,21 +848,7 @@ int main(int argc, char **argv) } } - pdfapp_close(&gapp); - - XDestroyWindow(xdpy, xwin); - - XFreePixmap(xdpy, xicon); - - XFreeCursor(xdpy, xcwait); - XFreeCursor(xdpy, xchand); - XFreeCursor(xdpy, xcarrow); - - XFreeGC(xdpy, xgc); - - XCloseDisplay(xdpy); - - fz_free_context(ctx); + cleanup(&gapp); return 0; } diff --git a/draw/draw_affine.c b/draw/draw_affine.c index 4e21ced0..52b8a847 100644 --- a/draw/draw_affine.c +++ b/draw/draw_affine.c @@ -653,14 +653,18 @@ fz_paint_image_imp(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap inv = fz_concat(inv, ctm); inv = fz_invert_matrix(inv); - fa = inv.a * 65536; - fb = inv.b * 65536; - fc = inv.c * 65536; - fd = inv.d * 65536; + fa = (int)(inv.a *= 65536.0f); + fb = (int)(inv.b *= 65536.0f); + fc = (int)(inv.c *= 65536.0f); + fd = (int)(inv.d *= 65536.0f); + inv.e *= 65536.0f; + inv.f *= 65536.0f; /* Calculate initial texture positions. Do a half step to start. */ - u = (fa * x) + (fc * y) + inv.e * 65536 + ((fa + fc) >> 1); - v = (fb * x) + (fd * y) + inv.f * 65536 + ((fb + fd) >> 1); + /* Bug 693021: Keep calculation in float for as long as possible to + * avoid overflow. */ + u = (int)((inv.a * x) + (inv.c * y) + inv.e + ((inv.a + inv.c) * .5f)); + v = (int)((inv.b * x) + (inv.d * y) + inv.f + ((inv.b + inv.d) * .5f)); /* RJW: The following is voodoo. No idea why it works, but it gives * the best match between scaled/unscaled/interpolated/non-interpolated diff --git a/draw/draw_simple_scale.c b/draw/draw_simple_scale.c index 8143b6fd..6f123ce3 100644 --- a/draw/draw_simple_scale.c +++ b/draw/draw_simple_scale.c @@ -807,17 +807,18 @@ scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, " @ r14= len = *contrib \n" "blt 4f @ while (x >= 0) { \n" #ifndef ARCH_ARM_CAN_LOAD_UNALIGNED - "tst r3, #3 @ if (r3 & 3) \n" - "blt 4f @ can't do fast code \n" + "tst r3, #3 @ if ((r3 & 3) \n" + "tsteq r1, #3 @ || (r1 & 3)) \n" + "bne 4f @ can't do fast code \n" #endif "ldr r9, =0x00FF00FF @ r9 = 0x00FF00FF \n" "1: \n" - "ldr r5, =0x00800080 @ r5 = val0 = round \n" - "stmfd r13!,{r1,r2} @ stash r1,r2,r14 \n" + "ldr r7, =0x00800080 @ r5 = val0 = round \n" + "stmfd r13!,{r1,r2,r7} @ stash r1,r2,r5 \n" " @ r1 = min = src \n" " @ r2 = contrib2-4 \n" "movs r8, r14 @ r8 = len2 = len \n" - "mov r7, r5 @ r7 = val1 = round \n" + "mov r5, r7 @ r7 = val1 = round \n" "ble 3f @ while (len2-- > 0) { \n" "2: \n" "ldr r12,[r1], r3 @ r12 = *min r5 = min += width\n" @@ -828,11 +829,11 @@ scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, "mla r5, r10,r11,r5 @ r5 = val0 += r11 * r10\n" "mla r7, r10,r12,r7 @ r7 = val1 += r12 * r10\n" "bgt 2b @ } \n" - "3: \n" - "ldmfd r13!,{r1,r2} @ restore r1,r2,r14 \n" "and r5, r9, r5, LSR #8 @ r5 = __22__00 \n" "and r7, r7, r9, LSL #8 @ r7 = 33__11__ \n" "orr r5, r5, r7 @ r5 = 33221100 \n" + "3: \n" + "ldmfd r13!,{r1,r2,r7} @ restore r1,r2,r7 \n" "subs r6, r6, #4 @ x-- \n" "add r1, r1, #4 @ src++ \n" "str r5, [r0], #4 @ *dst++ = val \n" diff --git a/fitz/doc_document.c b/fitz/doc_document.c index 07319d1d..74192908 100644 --- a/fitz/doc_document.c +++ b/fitz/doc_document.c @@ -136,3 +136,10 @@ fz_interactive *fz_interact(fz_document *doc) return doc->interact(doc); return NULL; } + +void +fz_write(fz_document *doc, char *filename, fz_write_options *opts) +{ + if (doc && doc->write) + doc->write(doc, filename, opts); +} diff --git a/fitz/filt_basic.c b/fitz/filt_basic.c index 09d63402..7d504f29 100644 --- a/fitz/filt_basic.c +++ b/fitz/filt_basic.c @@ -14,6 +14,7 @@ struct null_filter { fz_stream *chain; int remain; + int pos; }; static int @@ -21,8 +22,12 @@ read_null(fz_stream *stm, unsigned char *buf, int len) { struct null_filter *state = stm->state; int amount = MIN(len, state->remain); - int n = fz_read(state->chain, buf, amount); + int n; + + fz_seek(state->chain, state->pos, 0); + n = fz_read(state->chain, buf, amount); state->remain -= n; + state->pos += n; return n; } @@ -36,7 +41,7 @@ close_null(fz_context *ctx, void *state_) } fz_stream * -fz_open_null(fz_stream *chain, int len) +fz_open_null(fz_stream *chain, int len, int offset) { struct null_filter *state; fz_context *ctx = chain->ctx; @@ -46,6 +51,7 @@ fz_open_null(fz_stream *chain, int len) state = fz_malloc_struct(ctx, struct null_filter); state->chain = chain; state->remain = len; + state->pos = offset; } fz_catch(ctx) { @@ -56,6 +62,104 @@ fz_open_null(fz_stream *chain, int len) return fz_new_stream(ctx, state, read_null, close_null); } +/* Concat filter concatenates several streams into one */ + +struct concat_filter +{ + int max; + int count; + int current; + int pad; /* 1 if we should add whitespace padding between streams */ + int ws; /* 1 if we should send a whitespace padding byte next */ + fz_stream *chain[1]; +}; + +static int +read_concat(fz_stream *stm, unsigned char *buf, int len) +{ + struct concat_filter *state = (struct concat_filter *)stm->state; + int n; + int read = 0; + + if (len <= 0) + return 0; + + while (state->current != state->count && len > 0) + { + /* If we need to send a whitespace char, do that */ + if (state->ws) + { + *buf++ = 32; + read++; + len--; + state->ws = 0; + continue; + } + /* Otherwise, read as much data as will fit in the buffer */ + n = fz_read(state->chain[state->current], buf, len); + read += n; + buf += n; + len -= n; + /* If we didn't read any, then we must have hit the end of + * our buffer space. Move to the next stream, and remember to + * pad. */ + if (n == 0) + { + fz_close(state->chain[state->current]); + state->current++; + state->ws = state->pad; + } + } + + return read; +} + +static void +close_concat(fz_context *ctx, void *state_) +{ + struct concat_filter *state = (struct concat_filter *)state_; + int i; + + for (i = state->current; i < state->count; i++) + { + fz_close(state->chain[i]); + } + fz_free(ctx, state); +} + +fz_stream * +fz_open_concat(fz_context *ctx, int len, int pad) +{ + struct concat_filter *state; + + fz_try(ctx) + { + state = fz_calloc(ctx, 1, sizeof(struct concat_filter) + (len-1)*sizeof(fz_stream *)); + state->max = len; + state->count = 0; + state->current = 0; + state->pad = pad; + state->ws = 0; /* We never send padding byte at the start */ + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return fz_new_stream(ctx, state, read_concat, close_concat); +} + +void +fz_concat_push(fz_stream *concat, fz_stream *chain) +{ + struct concat_filter *state = (struct concat_filter *)concat->state; + + if (state->count == state->max) + fz_throw(concat->ctx, "Concat filter size exceeded"); + + state->chain[state->count++] = chain; +} + /* ASCII Hex Decode */ typedef struct fz_ahxd_s fz_ahxd; diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c index ada7e87b..febc6a65 100644 --- a/fitz/filt_faxd.c +++ b/fitz/filt_faxd.c @@ -57,7 +57,7 @@ enum }; /* White decoding table. */ -const cfd_node cf_white_decode[] = { +static const cfd_node cf_white_decode[] = { {256,12},{272,12},{29,8},{30,8},{45,8},{46,8},{22,7},{22,7}, {23,7},{23,7},{47,8},{48,8},{13,6},{13,6},{13,6},{13,6},{20,7}, {20,7},{33,8},{34,8},{35,8},{36,8},{37,8},{38,8},{19,7},{19,7}, @@ -95,7 +95,7 @@ const cfd_node cf_white_decode[] = { }; /* Black decoding table. */ -const cfd_node cf_black_decode[] = { +static const cfd_node cf_black_decode[] = { {128,12},{160,13},{224,12},{256,12},{10,7},{11,7},{288,12},{12,7}, {9,6},{9,6},{8,6},{8,6},{7,5},{7,5},{7,5},{7,5},{6,4},{6,4},{6,4}, {6,4},{6,4},{6,4},{6,4},{6,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4}, @@ -134,7 +134,7 @@ const cfd_node cf_black_decode[] = { }; /* 2-D decoding table. */ -const cfd_node cf_2d_decode[] = { +static const cfd_node cf_2d_decode[] = { {128,11},{144,10},{6,7},{0,7},{5,6},{5,6},{1,6},{1,6},{-4,4}, {-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-4,4},{-5,3},{-5,3}, {-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3},{-5,3}, @@ -153,7 +153,7 @@ const cfd_node cf_2d_decode[] = { }; /* Uncompressed decoding table. */ -const cfd_node cf_uncompressed_decode[] = { +static const cfd_node cf_uncompressed_decode[] = { {64,12},{5,6},{4,5},{4,5},{3,4},{3,4},{3,4},{3,4},{2,3},{2,3}, {2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{1,2},{1,2},{1,2},{1,2},{1,2}, {1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2},{1,2}, diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index 9dded182..21eb476d 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -411,7 +411,9 @@ void fz_grow_buffer(fz_context *ctx, fz_buffer *buf); void fz_trim_buffer(fz_context *ctx, fz_buffer *buf); /* - fz_buffer_printf: print formatted to a buffer, growing if necessary + fz_buffer_printf: print formatted to a buffer. The buffer will + grow, but the caller must ensure that no more than 256 bytes are + added to the buffer per call. */ void fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, char *fmt, ...); @@ -424,7 +426,6 @@ struct fz_stream_s int pos; int avail; int bits; - int locked; unsigned char *bp, *rp, *wp, *ep; void *state; int (*read)(fz_stream *stm, unsigned char *buf, int len); @@ -433,8 +434,6 @@ struct fz_stream_s unsigned char buf[4096]; }; -void fz_lock_stream(fz_stream *stm); - fz_stream *fz_new_stream(fz_context *ctx, void*, int(*)(fz_stream*, unsigned char*, int), void(*)(fz_context *, void *)); fz_stream *fz_keep_stream(fz_stream *stm); void fz_fill_buffer(fz_stream *stm); @@ -525,7 +524,9 @@ static inline int fz_is_eof_bits(fz_stream *stm) */ fz_stream *fz_open_copy(fz_stream *chain); -fz_stream *fz_open_null(fz_stream *chain, int len); +fz_stream *fz_open_null(fz_stream *chain, int len, int offset); +fz_stream *fz_open_concat(fz_context *ctx, int max, int pad); +void fz_concat_push(fz_stream *concat, fz_stream *chain); /* Ownership of chain is passed in */ fz_stream *fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen); fz_stream *fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen); fz_stream *fz_open_a85d(fz_stream *chain); @@ -1091,6 +1092,7 @@ struct fz_document_s void (*free_page)(fz_document *doc, fz_page *page); int (*meta)(fz_document *doc, int key, void *ptr, int size); fz_interactive *(*interact)(fz_document *doc); + void (*write)(fz_document *doc, char *filename, fz_write_options *opts); }; #endif diff --git a/fitz/fitz.h b/fitz/fitz.h index d8afce95..41b1881c 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -92,19 +92,32 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); /* Variadic macros, inline and restrict keywords + + inline is standard in C++, so don't touch the definition in this case. + For some compilers we can enable it within C too. */ +#ifndef __cplusplus #if __STDC_VERSION__ == 199901L /* C99 */ -#elif defined __cplusplus -#define restrict #elif _MSC_VER >= 1500 /* MSVC 9 or newer */ #define inline __inline -#define restrict __restrict #elif __GNUC__ >= 3 /* GCC 3 or newer */ #define inline __inline -#define restrict __restrict #else /* Unknown or ancient */ #define inline +#endif +#endif + +/* + restrict is standard in C99, but not in all C++ compilers. Enable + where possible, disable if in doubt. + */ +#if __STDC_VERSION__ == 199901L /* C99 */ +#elif _MSC_VER >= 1500 /* MSVC 9 or newer */ +#define restrict __restrict +#elif __GNUC__ >= 3 /* GCC 3 or newer */ +#define restrict __restrict +#else /* Unknown or ancient */ #define restrict #endif @@ -2363,4 +2376,51 @@ char *fz_widget_text_get_text(fz_widget_text *tw); */ void fz_widget_text_set_text(fz_widget_text *tw, char *text); + +typedef struct fz_write_options_s fz_write_options; + +/* + In calls to fz_write, the following options structure can be used + to control aspects of the writing process. This structure may grow + in future, and should be zero-filled to allow forwards compatiblity. +*/ +struct fz_write_options_s +{ + int doascii; /* If non-zero then attempt (where possible) to + make the output ascii. */ + int doexpand; /* Bitflags; each non zero bit indicates an aspect + of the file that should be 'expanded' on + writing. */ + int dogarbage; /* If non-zero then attempt (where possible) to + garbage collect the file before writing. */ +}; + +/* An enumeration of bitflags to use in the above 'doexpand' field of + fz_write_options. +*/ +enum +{ + fz_expand_images = 1, + fz_expand_fonts = 2, + fz_expand_all = -1 +}; + +/* + fz_write: Write a document out. + + (In development - Subject to change in future versions) + + Save a copy of the current document in its original format. + Internally the document may change. + + doc: The document to save. + + filename: The filename to save to. + + opts: NULL, or a pointer to an options structure. + + May throw exceptions. +*/ +void fz_write(fz_document *doc, char *filename, fz_write_options *opts); + #endif diff --git a/fitz/res_font.c b/fitz/res_font.c index a0c2fc2a..966cbc6e 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -56,7 +56,7 @@ fz_new_font(fz_context *ctx, char *name, int use_glyph_bbox, int glyph_count) else { if (use_glyph_bbox) - fz_warn(ctx, "not building glyph bbox table for font '%s' with %d glyphs", name, glyph_count); + fz_warn(ctx, "not building glyph bbox table for font '%s' with %d glyphs", font->name, glyph_count); font->bbox_count = 0; font->bbox_table = NULL; } @@ -692,7 +692,7 @@ static fz_rect fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) { fz_matrix ctm; - fz_buffer *contents; + void *contents; fz_rect bounds; fz_bbox bbox; fz_device *dev; @@ -726,7 +726,7 @@ fz_pixmap * fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model) { fz_matrix ctm; - fz_buffer *contents; + void *contents; fz_bbox bbox; fz_device *dev; fz_pixmap *glyph; @@ -786,7 +786,7 @@ void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate) { fz_matrix ctm; - fz_buffer *contents; + void *contents; if (gid < 0 || gid > 255) return; diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c index 9b7a542c..7be824f9 100644 --- a/fitz/stm_buffer.c +++ b/fitz/stm_buffer.c @@ -82,19 +82,14 @@ fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap) void fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, char *fmt, ...) { - int count; - int done = 0; va_list args; va_start(args, fmt); - while(!done) - { - count = vsnprintf(buffer->data + buffer->len, buffer->cap - buffer->len, fmt, args); - done = (count >= 0 && count < buffer->cap - buffer->len); - if (!done) - fz_grow_buffer(ctx, buffer); - } + /* Caller guarantees not to generate more than 256 bytes per call */ + while(buffer->cap - buffer->len < 256) + fz_grow_buffer(ctx, buffer); + + buffer->len += vsprintf(buffer->data + buffer->len, fmt, args); - buffer->len += count; va_end(args); } diff --git a/fitz/stm_open.c b/fitz/stm_open.c index ced32d80..be069fb9 100644 --- a/fitz/stm_open.c +++ b/fitz/stm_open.c @@ -24,7 +24,6 @@ fz_new_stream(fz_context *ctx, void *state, stm->bits = 0; stm->avail = 0; - stm->locked = 0; stm->bp = stm->buf; stm->rp = stm->bp; @@ -40,16 +39,6 @@ fz_new_stream(fz_context *ctx, void *state, return stm; } -void -fz_lock_stream(fz_stream *stm) -{ - if (stm) - { - fz_lock(stm->ctx, FZ_LOCK_FILE); - stm->locked = 1; - } -} - fz_stream * fz_keep_stream(fz_stream *stm) { @@ -67,8 +56,6 @@ fz_close(fz_stream *stm) { if (stm->close) stm->close(stm->ctx, stm->state); - if (stm->locked) - fz_unlock(stm->ctx, FZ_LOCK_FILE); fz_free(stm->ctx, stm); } } @@ -78,7 +65,6 @@ fz_close(fz_stream *stm) static int read_file(fz_stream *stm, unsigned char *buf, int len) { int n = read(*(int*)stm->state, buf, len); - fz_assert_lock_held(stm->ctx, FZ_LOCK_FILE); if (n < 0) fz_throw(stm->ctx, "read error: %s", strerror(errno)); return n; @@ -87,7 +73,6 @@ static int read_file(fz_stream *stm, unsigned char *buf, int len) static void seek_file(fz_stream *stm, int offset, int whence) { int n = lseek(*(int*)stm->state, offset, whence); - fz_assert_lock_held(stm->ctx, FZ_LOCK_FILE); if (n < 0) fz_throw(stm->ctx, "cannot lseek: %s", strerror(errno)); stm->pos = n; diff --git a/ios/Info.plist b/ios/Info.plist index 6afbcf12..1e29c114 100644 --- a/ios/Info.plist +++ b/ios/Info.plist @@ -48,5 +48,88 @@ <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> + <key>CFBundleDocumentTypes</key> + <array> + <dict> + <key>CFBundleTypeName</key> + <string>PDF</string> + <key>LSItemContentTypes</key> + <array> + <string>com.adobe.pdf</string> + </array> + <key>LSHandlerRank</key> + <string>Alternate</string> + </dict> + <dict> + <key>LSItemContentTypes</key> + <array> + <string>com.microsoft.xps</string> + </array> + <key>CFBundleTypeName</key> + <string>XPS</string> + <key>LSHandlerRank</key> + <string>Alternate</string> + </dict> + <dict> + <key>CFBundleTypeName</key> + <string>CBZ</string> + <key>LSItemContentTypes</key> + <array> + <string>public.zip-archive</string> + </array> + <key>LSHandlerRank</key> + <string>Alternate</string> + </dict> + </array> + <key>UTImportedTypeDeclarations</key> + <array> + <dict> + <key>UTTypeConformsTo</key> + <array> + <string>public.data</string> + </array> + <key>UTTypeIdentifier</key> + <string>com.microsoft.xps</string> + <key>UTTypeTagSpecification</key> + <dict> + <key>public.filename-extension</key> + <array> + <string>xps</string> + <string>oxps</string> + </array> + </dict> + </dict> + <dict> + <key>UTTypeConformsTo</key> + <array> + <string>public.data</string> + </array> + <key>UTTypeIdentifier</key> + <string>public.zip-archive</string> + <key>UTTypeTagSpecification</key> + <dict> + <key>public.filename-extension</key> + <array> + <string>zip</string> + <string>cbz</string> + </array> + </dict> + </dict> + <dict> + <key>UTTypeConformsTo</key> + <array> + <string>public.data</string> + </array> + <key>UTTypeIdentifier</key> + <string>com.adobe.pdf</string> + <key>UTTypeTagSpecification</key> + <dict> + <key>public.filename-extension</key> + <array> + <string>pdf</string> + </array> + </dict> + </dict> + </array> </dict> </plist> @@ -272,10 +272,10 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, - (void) viewWillAppear: (BOOL)animated { - [self setTitle: @"PDF and XPS Documents"]; + [self setTitle: @"PDF, XPS and CBZ Documents"]; [self reload]; printf("library viewWillAppear (starting reload timer)\n"); - timer = [NSTimer timerWithTimeInterval: 1 + timer = [NSTimer timerWithTimeInterval: 3 target: self selector: @selector(reload) userInfo: nil repeats: YES]; [[NSRunLoop currentRunLoop] addTimer: timer forMode: NSDefaultRunLoopMode]; @@ -290,18 +290,26 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, - (void) reload { - NSError *error = nil; - if (files) { [files release]; files = nil; } + NSFileManager *fileman = [NSFileManager defaultManager]; NSString *docdir = [NSString stringWithFormat: @"%@/Documents", NSHomeDirectory()]; - files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath: docdir error: &error]; - if (error) - files = [NSArray arrayWithObjects: @"...error loading directory...", nil]; - [files retain]; + NSMutableArray *outfiles = [[NSMutableArray alloc] init]; + NSDirectoryEnumerator *direnum = [fileman enumeratorAtPath:docdir]; + NSString *file; + BOOL isdir; + while (file = [direnum nextObject]) { + NSString *filepath = [docdir stringByAppendingPathComponent:file]; + NSLog(@"file %@\n", file); + if ([fileman fileExistsAtPath:filepath isDirectory:&isdir] && !isdir) { + [outfiles addObject:file]; + } + } + + files = outfiles; [[self tableView] reloadData]; } @@ -1386,6 +1394,8 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, - (BOOL) application: (UIApplication*)application didFinishLaunchingWithOptions: (NSDictionary*)launchOptions { + NSString *filename; + queue = dispatch_queue_create("com.artifex.mupdf.queue", NULL); // use at most 128M for resource cache @@ -1405,13 +1415,31 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, [window addSubview: [navigator view]]; [window makeKeyAndVisible]; - NSString *filename = [[NSUserDefaults standardUserDefaults] objectForKey: @"OpenDocumentKey"]; + filename = [[NSUserDefaults standardUserDefaults] objectForKey: @"OpenDocumentKey"]; if (filename) [library openDocument: filename]; + filename = [launchOptions objectForKey: UIApplicationLaunchOptionsURLKey]; + NSLog(@"urlkey = %@\n", filename); + return YES; } +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation +{ + NSLog(@"openURL: %@\n", url); + if ([url isFileURL]) { + NSString *path = [url path]; + NSString *dir = [NSString stringWithFormat: @"%@/Documents/", NSHomeDirectory()]; + path = [path stringByReplacingOccurrencesOfString:@"/private" withString:@""]; + path = [path stringByReplacingOccurrencesOfString:dir withString:@""]; + NSLog(@"file relative path: %@\n", path); + [library openDocument:path]; + return YES; + } + return NO; +} + - (void)applicationDidEnterBackground:(UIApplication *)application { printf("applicationDidEnterBackground!\n"); diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h index b50ba2fe..b1117726 100644 --- a/pdf/mupdf-internal.h +++ b/pdf/mupdf-internal.h @@ -146,11 +146,12 @@ typedef struct pdf_xref_entry_s pdf_xref_entry; struct pdf_xref_entry_s { + char type; /* 0=unset (f)ree i(n)use (o)bjstm */ int ofs; /* file offset / objstm object number */ int gen; /* generation / objstm index */ int stm_ofs; /* on-disk stream */ + fz_buffer *stm_buf; /* in-memory stream (for updated objects) */ pdf_obj *obj; /* stored/cached object */ - int type; /* 0=unset (f)ree i(n)use (o)bjstm */ }; typedef struct pdf_crypt_s pdf_crypt; @@ -217,19 +218,25 @@ struct pdf_document_s pdf_js *js; }; +pdf_document *pdf_open_document_no_run(fz_context *ctx, const char *filename); +pdf_document *pdf_open_document_no_run_with_stream(fz_stream *file); + void pdf_cache_object(pdf_document *doc, int num, int gen); fz_stream *pdf_open_inline_stream(pdf_document *doc, pdf_obj *stmobj, int length, fz_stream *chain, pdf_image_params *params); -fz_buffer *pdf_load_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); -fz_stream *pdf_open_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); +fz_buffer *pdf_load_image_stream(pdf_document *doc, int num, int gen, int orig_num, int orig_gen, pdf_image_params *params); +fz_stream *pdf_open_image_stream(pdf_document *doc, int num, int gen, int orig_num, int orig_gen, pdf_image_params *params); fz_stream *pdf_open_stream_with_offset(pdf_document *doc, int num, int gen, pdf_obj *dict, int stm_ofs); fz_stream *pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *, pdf_image_params *params, int *factor); +fz_stream *pdf_open_contents_stream(pdf_document *xref, pdf_obj *obj); +fz_buffer *pdf_load_raw_renumbered_stream(pdf_document *doc, int num, int gen, int orig_num, int orig_gen); +fz_buffer *pdf_load_renumbered_stream(pdf_document *doc, int num, int gen, int orig_num, int orig_gen); +fz_stream *pdf_open_raw_renumbered_stream(pdf_document *doc, int num, int gen, int orig_num, int orig_gen); void pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf); void pdf_repair_obj_stms(pdf_document *doc); void pdf_print_xref(pdf_document *); void pdf_resize_xref(pdf_document *doc, int newcap); -pdf_obj *pdf_new_stream_indirection(pdf_document *doc, pdf_obj *obj); /* * Encryption @@ -239,6 +246,7 @@ pdf_crypt *pdf_new_crypt(fz_context *ctx, pdf_obj *enc, pdf_obj *id); void pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt); void pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, int num, int gen); +void pdf_crypt_buffer(fz_context *ctx, pdf_crypt *crypt, fz_buffer *buf, int num, int gen); fz_stream *pdf_open_crypt(fz_stream *chain, pdf_crypt *crypt, int num, int gen); fz_stream *pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int num, int gen); @@ -284,7 +292,7 @@ struct pdf_pattern_s fz_matrix matrix; fz_rect bbox; pdf_obj *resources; - fz_buffer *contents; + pdf_obj *contents; }; pdf_pattern *pdf_load_pattern(pdf_document *doc, pdf_obj *obj); @@ -307,7 +315,7 @@ struct pdf_xobject_s int transparency; fz_colorspace *colorspace; pdf_obj *resources; - fz_buffer *contents; + pdf_obj *contents; pdf_obj *me; }; @@ -315,7 +323,7 @@ pdf_xobject *pdf_load_xobject(pdf_document *doc, pdf_obj *obj); pdf_obj *pdf_new_xobject(pdf_document *doc, fz_rect *bbox, fz_matrix *mat); pdf_xobject *pdf_keep_xobject(fz_context *ctx, pdf_xobject *xobj); void pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj); -void pdf_xobject_set_contents(fz_context *ctx, pdf_xobject *from, fz_buffer *buffer); +void pdf_xobject_set_contents(pdf_document *xref, pdf_xobject *from, fz_buffer *buffer); void pdf_update_appearance(pdf_document *doc, pdf_obj *obj); @@ -553,7 +561,7 @@ struct pdf_page_s int rotate; int transparency; pdf_obj *resources; - fz_buffer *contents; + pdf_obj *contents; fz_link *links; pdf_annot *annots; }; diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 2d27f4af..2d93b793 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -20,7 +20,6 @@ pdf_obj *pdf_new_real(fz_context *ctx, float f); pdf_obj *fz_new_name(fz_context *ctx, char *str); pdf_obj *pdf_new_string(fz_context *ctx, char *str, int len); pdf_obj *pdf_new_indirect(fz_context *ctx, int num, int gen, void *doc); - pdf_obj *pdf_new_array(fz_context *ctx, int initialcap); pdf_obj *pdf_new_dict(fz_context *ctx, int initialcap); pdf_obj *pdf_new_rect(fz_context *ctx, fz_rect *rect); @@ -97,7 +96,6 @@ fz_matrix pdf_to_matrix(fz_context *ctx, pdf_obj *array); int pdf_count_objects(pdf_document *doc); pdf_obj *pdf_resolve_indirect(pdf_obj *ref); pdf_obj *pdf_load_object(pdf_document *doc, int num, int gen); -void pdf_update_object(pdf_document *doc, int num, int gen, pdf_obj *newobj); fz_buffer *pdf_load_raw_stream(pdf_document *doc, int num, int gen); fz_buffer *pdf_load_stream(pdf_document *doc, int num, int gen); @@ -109,6 +107,41 @@ fz_image *pdf_load_image(pdf_document *doc, pdf_obj *obj); fz_outline *pdf_load_outline(pdf_document *doc); /* + pdf_create_object: Allocate a slot in the xref table and return a fresh unused object number. +*/ +int pdf_create_object(pdf_document *xref); + +/* + pdf_delete_object: Remove object from xref table, marking the slot as free. +*/ +void pdf_delete_object(pdf_document *xref, int num); + +/* + pdf_update_object: Replace object in xref table with the passed in object. +*/ +void pdf_update_object(pdf_document *xref, int num, pdf_obj *obj); + +/* + pdf_get_stream: Return the contents for object in xref table +*/ +fz_buffer *pdf_get_stream(pdf_document *xref, int num); + +/* + pdf_update_stream: Replace stream contents for object in xref table with the passed in buffer. + + The buffer contents must match the /Filter setting. + If storing uncompressed data, make sure to delete the /Filter key from + the stream dictionary. If storing deflated data, make sure to set the + /Filter value to /FlateDecode. +*/ +void pdf_update_stream(pdf_document *xref, int num, fz_buffer *buf); + +/* + pdf_write_document: Write out the document to a file with all changes finalised. +*/ +void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *opts); + +/* pdf_open_document: Open a PDF document. Open a PDF document by reading its cross reference table, so @@ -218,4 +251,9 @@ void pdf_run_page(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix c void pdf_run_page_with_usage(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie); +/* + Metadata interface. +*/ +int pdf_meta(pdf_document *doc, int key, void *ptr, int size); + #endif diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c index 71066986..1f1117fe 100644 --- a/pdf/pdf_cmap.c +++ b/pdf/pdf_cmap.c @@ -189,7 +189,7 @@ add_table(fz_context *ctx, pdf_cmap *cmap, int value) } if (cmap->tlen + 1 > cmap->tcap) { - int new_cap = cmap->tcap > 1 ? (cmap->tcap * 3) / 2 : 256; + int new_cap = cmap->tcap > 1 ? (cmap->tcap * 3) / 2 : 256; cmap->table = fz_resize_array(ctx, cmap->table, new_cap, sizeof(unsigned short)); cmap->tcap = new_cap; } diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index ab60af72..9e4e60ea 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -148,7 +148,7 @@ static int ft_width(fz_context *ctx, pdf_font_desc *fontdesc, int cid) { int gid = ft_cid_to_gid(fontdesc, cid); int fterr; - + fterr = FT_Load_Glyph(fontdesc->font->ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c index 92eda83f..a517c339 100644 --- a/pdf/pdf_form.c +++ b/pdf/pdf_form.c @@ -71,6 +71,11 @@ static const char *fmt_ET = "ET\n"; static const char *fmt_Q = "Q\n"; static const char *fmt_EMC = "EMC\n"; +static fz_buffer *form_contents(pdf_document *doc, pdf_xobject *form) +{ + return pdf_get_stream(doc, pdf_to_num(form->contents)); +} + static void account_for_rot(fz_rect *rect, fz_matrix *mat, int rot) { float width = rect->x1; @@ -659,8 +664,9 @@ fz_buffer *create_text_appearance(pdf_document *doc, fz_rect *bbox, fz_matrix *o return fzbuf; } -static void update_marked_content(fz_context *ctx, pdf_xobject *form, fz_buffer *fzbuf) +static void update_marked_content(pdf_document *doc, pdf_xobject *form, fz_buffer *fzbuf) { + fz_context *ctx = doc->ctx; int tok; pdf_lexbuf lbuf; fz_stream *str_outer = NULL; @@ -681,7 +687,7 @@ static void update_marked_content(fz_context *ctx, pdf_xobject *form, fz_buffer int first = 1; newbuf = fz_new_buffer(ctx, 0); - len = fz_buffer_storage(ctx, form->contents, &buf); + len = fz_buffer_storage(ctx, form_contents(doc, form), &buf); str_outer = fz_open_memory(ctx, buf, len); len = fz_buffer_storage(ctx, fzbuf, &buf); str_inner = fz_open_memory(ctx, buf, len); @@ -733,7 +739,7 @@ static void update_marked_content(fz_context *ctx, pdf_xobject *form, fz_buffer } /* Use newbuf in place of the existing appearance stream */ - pdf_xobject_set_contents(ctx, form, newbuf); + pdf_xobject_set_contents(doc, form, newbuf); } fz_always(ctx) { @@ -756,7 +762,7 @@ int get_matrix(pdf_document *doc, pdf_xobject *form, int q, fz_matrix *mt) pdf_lexbuf lbuf; fz_stream *str; - bufsize = fz_buffer_storage(ctx, form->contents, &buf); + bufsize = fz_buffer_storage(ctx, form_contents(doc, form), &buf); str = fz_open_memory(ctx, buf, bufsize); memset(lbuf.scratch, 0, sizeof(lbuf.scratch)); @@ -807,7 +813,7 @@ int get_matrix(pdf_document *doc, pdf_xobject *form, int q, fz_matrix *mt) if (q != Q_Left) { /* Offset the matrix to refer to the alignment position */ - fz_rect bbox = measure_text(doc, form->resources, form->contents); + fz_rect bbox = measure_text(doc, form->resources, form_contents(doc, form)); mt->e += q == Q_Right ? (bbox.x1 - bbox.x0) : (bbox.x1 - bbox.x0) / 2; } @@ -859,7 +865,7 @@ static void update_text_appearance(pdf_document *doc, pdf_obj *obj, char *text) has_tm = get_matrix(doc, form, q, &tm); fzbuf = create_text_appearance(doc, &form->bbox, has_tm ? &tm : NULL, q, dr, pdf_to_str_buf(da), text); - update_marked_content(ctx, form, fzbuf); + update_marked_content(doc, form, fzbuf); } } } @@ -921,7 +927,7 @@ static void synthesize_text_widget(pdf_document *doc, pdf_obj *obj) form = pdf_load_xobject(doc, formobj); fzbuf = fz_new_buffer(ctx, 0); fz_buffer_printf(ctx, fzbuf, "/Tx BMC EMC"); - pdf_xobject_set_contents(ctx, form, fzbuf); + pdf_xobject_set_contents(doc, form, fzbuf); ap = pdf_new_dict(ctx, 1); pdf_dict_puts(ap, "N", formobj); @@ -1145,7 +1151,7 @@ static void update_pushbutton_widget(pdf_document *doc, pdf_obj *obj) fzbuf_print_text(ctx, fzbuf, &clip, da, 0, &mat, text); } - pdf_xobject_set_contents(ctx, form, fzbuf); + pdf_xobject_set_contents(doc, form, fzbuf); } fz_always(ctx) { diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index dc9cc088..b4571bbe 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -95,7 +95,7 @@ static fz_store_type pdf_image_store_type = }; static fz_pixmap * -decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int factor) +decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int factor, int cache) { fz_pixmap *tile = NULL; fz_pixmap *existing_tile; @@ -190,6 +190,9 @@ decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int fz_rethrow(ctx); } + if (!cache) + return tile; + /* Now we try to cache the pixmap. Any failure here will just result * in us not caching. */ fz_try(ctx) @@ -279,7 +282,7 @@ pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h) /* We need to make a new one. */ stm = pdf_open_image_decomp_stream(ctx, image->buffer, &image->params, &factor); - return decomp_image_from_stream(ctx, stm, image, 0, 0, factor); + return decomp_image_from_stream(ctx, stm, image, 0, 0, factor, 1); } static pdf_image * @@ -427,7 +430,9 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c { /* Just load the compressed image data now and we can * decode it on demand. */ - image->buffer = pdf_load_image_stream(xref, pdf_to_num(dict), pdf_to_gen(dict), &image->params); + int num = pdf_to_num(dict); + int gen = pdf_to_gen(dict); + image->buffer = pdf_load_image_stream(xref, num, gen, num, gen, &image->params); break; /* Out of fz_try */ } @@ -443,7 +448,7 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c /* RJW: "cannot open image data stream (%d 0 R)", pdf_to_num(dict) */ } - image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 1); + image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 1, 0); } fz_catch(ctx) { diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index a11b8c30..8851be6e 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -104,7 +104,7 @@ struct pdf_csi_s fz_cookie *cookie; }; -static void pdf_run_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents); +static void pdf_run_contents_object(pdf_csi *csi, pdf_obj *rdb, pdf_obj *contents); static void pdf_run_xobject(pdf_csi *csi, pdf_obj *resources, pdf_xobject *xobj, fz_matrix transform); static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what); @@ -1291,7 +1291,7 @@ pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what) gstate->ctm = ptm; csi->top_ctm = gstate->ctm; pdf_gsave(csi); - pdf_run_buffer(csi, pat->resources, pat->contents); + pdf_run_contents_object(csi, pat->resources, pat->contents); /* RJW: "cannot render pattern tile" */ pdf_grestore(csi); while (oldtop < csi->gtop) @@ -1310,7 +1310,7 @@ pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what) pdf_gsave(csi); fz_try(ctx) { - pdf_run_buffer(csi, pat->resources, pat->contents); + pdf_run_contents_object(csi, pat->resources, pat->contents); } fz_catch(ctx) { @@ -1407,7 +1407,7 @@ pdf_run_xobject(pdf_csi *csi, pdf_obj *resources, pdf_xobject *xobj, fz_matrix t if (xobj->resources) resources = xobj->resources; - pdf_run_buffer(csi, resources, xobj->contents); + pdf_run_contents_object(csi, resources, xobj->contents); /* RJW: "cannot interpret XObject stream" */ } fz_always(ctx) @@ -2528,7 +2528,6 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf) fz_warn(ctx, "unknown keyword: '%s'", buf); break; } - fz_assert_lock_not_held(ctx, FZ_LOCK_FILE); } static void @@ -2662,44 +2661,78 @@ pdf_run_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, pdf_lexbuf *buf) */ static void -pdf_run_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents) +pdf_run_contents_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file) { fz_context *ctx = csi->dev->ctx; pdf_lexbuf_large *buf; - fz_stream * file = NULL; int save_in_text; fz_var(buf); - fz_var(file); + + if (file == NULL) + return; + + buf = fz_malloc(ctx, sizeof(*buf)); /* we must be re-entrant for type3 fonts */ + buf->base.size = PDF_LEXBUF_LARGE; + save_in_text = csi->in_text; + csi->in_text = 0; + fz_try(ctx) + { + pdf_run_stream(csi, rdb, file, &buf->base); + } + fz_catch(ctx) + { + fz_warn(ctx, "Content stream parsing error - rendering truncated"); + } + csi->in_text = save_in_text; + fz_free(ctx, buf); +} + +static void +pdf_run_contents_object(pdf_csi *csi, pdf_obj *rdb, pdf_obj *contents) +{ + fz_context *ctx = csi->dev->ctx; + fz_stream *file = NULL; if (contents == NULL) return; + file = pdf_open_contents_stream(csi->xref, contents); fz_try(ctx) { - buf = fz_malloc(ctx, sizeof(*buf)); /* we must be re-entrant for type3 fonts */ - buf->base.size = PDF_LEXBUF_LARGE; - file = fz_open_buffer(ctx, contents); - save_in_text = csi->in_text; - csi->in_text = 0; - fz_try(ctx) - { - pdf_run_stream(csi, rdb, file, &buf->base); - } - fz_catch(ctx) - { - fz_warn(ctx, "Content stream parsing error - rendering truncated"); - } - csi->in_text = save_in_text; + pdf_run_contents_stream(csi, rdb, file); } fz_always(ctx) { fz_close(file); - fz_free(ctx, buf); } fz_catch(ctx) { - fz_throw(ctx, "cannot parse context stream"); + fz_rethrow(ctx); + } +} + +static void +pdf_run_contents_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents) +{ + fz_context *ctx = csi->dev->ctx; + fz_stream *file = NULL; + + if (contents == NULL) + return; + + file = fz_open_buffer(ctx, contents); + fz_try(ctx) + { + pdf_run_contents_stream(csi, rdb, file); + } + fz_always(ctx) + { + fz_close(file); + } + fz_catch(ctx) + { + fz_rethrow(ctx); } } @@ -2719,14 +2752,16 @@ pdf_run_page_with_usage(pdf_document *xref, pdf_page *page, fz_device *dev, fz_m csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL); fz_try(ctx) { - pdf_run_buffer(csi, page->resources, page->contents); + pdf_run_contents_object(csi, page->resources, page->contents); } - fz_catch(ctx) + fz_always(ctx) { pdf_free_csi(csi); + } + fz_catch(ctx) + { fz_throw(ctx, "cannot parse page content stream"); } - pdf_free_csi(csi); if (cookie && cookie->progress_max != -1) { @@ -2792,7 +2827,7 @@ pdf_run_glyph(pdf_document *xref, pdf_obj *resources, fz_buffer *contents, fz_de fz_try(ctx) { - pdf_run_buffer(csi, resources, contents); + pdf_run_contents_buffer(csi, resources, contents); } fz_catch(ctx) { diff --git a/pdf/pdf_js_none.c b/pdf/pdf_js_none.c index a85103e4..bc8d2ee7 100644 --- a/pdf/pdf_js_none.c +++ b/pdf/pdf_js_none.c @@ -13,6 +13,10 @@ void pdf_drop_js(pdf_js *js) { } +void pdf_js_setup_event(pdf_js *js, pdf_obj *target) +{ +} + void pdf_js_execute(pdf_js *js, char *code) { } diff --git a/pdf/base_object.c b/pdf/pdf_object.c index 142bc128..3fb48019 100644 --- a/pdf/base_object.c +++ b/pdf/pdf_object.c @@ -145,8 +145,8 @@ pdf_new_indirect(fz_context *ctx, int num, int gen, void *xref) pdf_obj * pdf_keep_obj(pdf_obj *obj) { - assert(obj); - obj->refs ++; + if (obj) + obj->refs ++; return obj; } @@ -159,7 +159,6 @@ int pdf_is_indirect(pdf_obj *obj) do { \ if (obj && obj->kind == PDF_INDIRECT) \ {\ - fz_assert_lock_not_held(obj->ctx, FZ_LOCK_FILE); \ obj = pdf_resolve_indirect(obj); \ } \ } while (0) @@ -566,6 +565,8 @@ pdf_obj *pdf_new_rect(fz_context *ctx, fz_rect *rect) pdf_obj *arr = NULL; pdf_obj *item = NULL; + fz_var(arr); + fz_var(item); fz_try(ctx) { arr = pdf_new_array(ctx, 4); @@ -605,6 +606,8 @@ pdf_obj *pdf_new_matrix(fz_context *ctx, fz_matrix *mtx) pdf_obj *arr = NULL; pdf_obj *item = NULL; + fz_var(arr); + fz_var(item); fz_try(ctx) { arr = pdf_new_array(ctx, 6); diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c index 3e95e9a5..39554551 100644 --- a/pdf/pdf_page.c +++ b/pdf/pdf_page.c @@ -114,6 +114,8 @@ pdf_load_page_tree_node(pdf_document *xref, pdf_obj *node, struct info info) } } /* Get the next node */ + if (stacklen < 0) + break; while (++stack[stacklen].pos == stack[stacklen].max) { pdf_dict_unmark(stack[stacklen].node); @@ -279,72 +281,6 @@ found: return useBM; } -/* we need to combine all sub-streams into one for the content stream interpreter */ - -static fz_buffer * -pdf_load_page_contents_array(pdf_document *xref, pdf_obj *list) -{ - fz_buffer *big; - fz_buffer *one; - int i, n; - fz_context *ctx = xref->ctx; - - big = fz_new_buffer(ctx, 32 * 1024); - - n = pdf_array_len(list); - fz_var(i); /* Workaround Mac compiler bug */ - for (i = 0; i < n; i++) - { - pdf_obj *stm = pdf_array_get(list, i); - fz_try(ctx) - { - one = pdf_load_stream(xref, pdf_to_num(stm), pdf_to_gen(stm)); - } - fz_catch(ctx) - { - fz_warn(ctx, "cannot load content stream part %d/%d", i + 1, n); - continue; - } - - if (big->len + one->len + 1 > big->cap) - fz_resize_buffer(ctx, big, big->len + one->len + 1); - memcpy(big->data + big->len, one->data, one->len); - big->data[big->len + one->len] = ' '; - big->len += one->len + 1; - - fz_drop_buffer(ctx, one); - } - - if (n > 0 && big->len == 0) - { - fz_drop_buffer(ctx, big); - fz_throw(ctx, "cannot load content stream"); - } - fz_trim_buffer(ctx, big); - - return big; -} - -static fz_buffer * -pdf_load_page_contents(pdf_document *xref, pdf_obj *obj) -{ - fz_context *ctx = xref->ctx; - - if (pdf_is_array(obj)) - { - return pdf_load_page_contents_array(xref, obj); - /* RJW: "cannot load content stream array" */ - } - else if (pdf_is_stream(xref, pdf_to_num(obj), pdf_to_gen(obj))) - { - return pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); - /* RJW: "cannot load content stream (%d 0 R)", pdf_to_num(obj) */ - } - - fz_warn(ctx, "page contents missing, leaving page blank"); - return fz_new_buffer(ctx, 0); -} - pdf_page * pdf_load_page(pdf_document *xref, int number) { @@ -422,7 +358,7 @@ pdf_load_page(pdf_document *xref, int number) obj = pdf_dict_gets(pageobj, "Contents"); fz_try(ctx) { - page->contents = pdf_load_page_contents(xref, obj); + page->contents = pdf_keep_obj(obj); if (pdf_resources_use_blending(ctx, page->resources)) page->transparency = 1; @@ -462,7 +398,7 @@ pdf_free_page(pdf_document *xref, pdf_page *page) if (page->resources) pdf_drop_obj(page->resources); if (page->contents) - fz_drop_buffer(xref->ctx, page->contents); + pdf_drop_obj(page->contents); if (page->links) fz_drop_link(xref->ctx, page->links); if (page->annots) diff --git a/pdf/pdf_parse.c b/pdf/pdf_parse.c index fe9db368..b1472d1a 100644 --- a/pdf/pdf_parse.c +++ b/pdf/pdf_parse.c @@ -453,21 +453,19 @@ pdf_parse_ind_obj(pdf_document *xref, fz_var(obj); tok = pdf_lex(file, buf); - /* RJW: cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_INT) - fz_throw(ctx, "expected object number (%d %d R)", num, gen); + fz_throw(ctx, "expected object number"); num = buf->i; tok = pdf_lex(file, buf); - /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_INT) - fz_throw(ctx, "expected generation number (%d %d R)", num, gen); + fz_throw(ctx, "expected generation number (%d ? obj)", num); gen = buf->i; tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_OBJ) - fz_throw(ctx, "expected 'obj' keyword (%d %d R)", num, gen); + fz_throw(ctx, "expected 'obj' keyword (%d %d ?)", num, gen); tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c index 14175670..af96c2d5 100644 --- a/pdf/pdf_pattern.c +++ b/pdf/pdf_pattern.c @@ -21,7 +21,7 @@ pdf_free_pattern_imp(fz_context *ctx, fz_storable *pat_) if (pat->resources) pdf_drop_obj(pat->resources); if (pat->contents) - fz_drop_buffer(ctx, pat->contents); + pdf_drop_obj(pat->contents); fz_free(ctx, pat); } @@ -30,7 +30,7 @@ pdf_pattern_size(pdf_pattern *pat) { if (pat == NULL) return 0; - return sizeof(*pat) + (pat->contents ? pat->contents->cap : 0); + return sizeof(*pat); } pdf_pattern * @@ -72,7 +72,7 @@ pdf_load_pattern(pdf_document *xref, pdf_obj *dict) fz_try(ctx) { - pat->contents = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); + pat->contents = pdf_keep_obj(dict); } fz_catch(ctx) { diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c index a51b9631..27846855 100644 --- a/pdf/pdf_repair.c +++ b/pdf/pdf_repair.c @@ -195,6 +195,7 @@ pdf_repair_obj_stm(pdf_document *xref, int num, int gen) } } +/* Entered with file locked, remains locked throughout. */ void pdf_repair_xref(pdf_document *xref, pdf_lexbuf *buf) { @@ -389,19 +390,7 @@ pdf_repair_xref(pdf_document *xref, pdf_lexbuf *buf) /* corrected stream length */ if (list[i].stm_len >= 0) { - fz_unlock(ctx, FZ_LOCK_FILE); - fz_try(ctx) - { - dict = pdf_load_object(xref, list[i].num, list[i].gen); - } - fz_always(ctx) - { - fz_lock(ctx, FZ_LOCK_FILE); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } + dict = pdf_load_object(xref, list[i].num, list[i].gen); /* RJW: "cannot load stream object (%d %d R)", list[i].num, list[i].gen */ length = pdf_new_int(ctx, list[i].stm_len); diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c index 84f966ec..89d94004 100644 --- a/pdf/pdf_stream.c +++ b/pdf/pdf_stream.c @@ -13,7 +13,7 @@ pdf_is_stream(pdf_document *xref, int num, int gen) pdf_cache_object(xref, num, gen); /* RJW: "cannot load object, ignoring error" */ - return xref->table[num].stm_ofs > 0; + return xref->table[num].stm_ofs > 0 || xref->table[num].stm_buf; } /* @@ -222,21 +222,27 @@ build_filter_chain(fz_stream *chain, pdf_document *xref, pdf_obj *fs, pdf_obj *p /* * 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. + * This is a null filter to constrain reading to the stream length (and to + * allow for other people accessing the file), followed by a decryption + * filter. + * + * num and gen are used purely to seed the encryption. */ static fz_stream * -pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen) +pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen, int offset) { + fz_context *ctx = chain->ctx; int hascrypt; int len; - fz_context *ctx = chain->ctx; + + if (num > 0 && num < xref->len && xref->table[num].stm_buf) + return fz_open_buffer(ctx, xref->table[num].stm_buf); /* don't close chain when we close this filter */ fz_keep_stream(chain); len = pdf_to_int(pdf_dict_gets(stmobj, "Length")); - chain = fz_open_null(chain, len); + chain = fz_open_null(chain, len, offset); fz_try(ctx) { @@ -258,7 +264,7 @@ pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int n * to stream length and decrypting. */ static fz_stream * -pdf_open_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen, pdf_image_params *imparams) +pdf_open_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen, int offset, pdf_image_params *imparams) { pdf_obj *filters; pdf_obj *params; @@ -266,14 +272,13 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, filters = pdf_dict_getsa(stmobj, "Filter", "F"); params = pdf_dict_getsa(stmobj, "DecodeParms", "DP"); - chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen); + chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen, offset); if (pdf_is_name(filters)) chain = build_filter(chain, xref, filters, params, num, gen, imparams); else if (pdf_array_len(filters) > 0) chain = build_filter_chain(chain, xref, filters, params, num, gen, imparams); - fz_lock_stream(chain); return chain; } @@ -298,20 +303,22 @@ pdf_open_inline_stream(pdf_document *xref, pdf_obj *stmobj, int length, fz_strea if (pdf_array_len(filters) > 0) return build_filter_chain(chain, xref, filters, params, 0, 0, imparams); - return fz_open_null(chain, length); + return fz_open_null(chain, length, fz_tell(chain)); } /* * Open a stream for reading the raw (compressed but decrypted) data. - * Using xref->file while this is open is a bad idea. */ fz_stream * pdf_open_raw_stream(pdf_document *xref, int num, int gen) { - pdf_xref_entry *x; - fz_stream *stm; + return pdf_open_raw_renumbered_stream(xref, num, gen, num, gen); +} - fz_var(x); +fz_stream * +pdf_open_raw_renumbered_stream(pdf_document *xref, int num, int gen, int orig_num, int orig_gen) +{ + pdf_xref_entry *x; if (num < 0 || num >= xref->len) fz_throw(xref->ctx, "object id out of range (%d %d R)", num, gen); @@ -324,10 +331,7 @@ pdf_open_raw_stream(pdf_document *xref, int num, int gen) if (x->stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_raw_filter(xref->file, xref, x->obj, num, gen); - fz_lock_stream(stm); - fz_seek(xref->file, x->stm_ofs, 0); - return stm; + return pdf_open_raw_filter(xref->file, xref, x->obj, orig_num, orig_gen, x->stm_ofs); } /* @@ -338,14 +342,13 @@ pdf_open_raw_stream(pdf_document *xref, int num, int gen) fz_stream * pdf_open_stream(pdf_document *xref, int num, int gen) { - return pdf_open_image_stream(xref, num, gen, NULL); + return pdf_open_image_stream(xref, num, gen, num, gen, NULL); } fz_stream * -pdf_open_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +pdf_open_image_stream(pdf_document *xref, int num, int gen, int orig_num, int orig_gen, pdf_image_params *params) { pdf_xref_entry *x; - fz_stream *stm; if (num < 0 || num >= xref->len) fz_throw(xref->ctx, "object id out of range (%d %d R)", num, gen); @@ -355,12 +358,10 @@ pdf_open_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *pa pdf_cache_object(xref, num, gen); /* RJW: "cannot load stream object (%d %d R)", num, gen */ - if (x->stm_ofs == 0) + if (x->stm_ofs == 0 && x->stm_buf == NULL) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, x->obj, num, gen, params); - fz_seek(xref->file, x->stm_ofs, 0); - return stm; + return pdf_open_filter(xref->file, xref, x->obj, orig_num, orig_gen, x->stm_ofs, params); } fz_stream * @@ -410,14 +411,10 @@ pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *buffer, pdf_image_param fz_stream * pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, pdf_obj *dict, int stm_ofs) { - fz_stream *stm; - if (stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, dict, num, gen, NULL); - fz_seek(xref->file, stm_ofs, 0); - return stm; + return pdf_open_filter(xref->file, xref, dict, num, gen, stm_ofs, NULL); } /* @@ -426,11 +423,20 @@ pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, pdf_obj *dict, fz_buffer * pdf_load_raw_stream(pdf_document *xref, int num, int gen) { + return pdf_load_raw_renumbered_stream(xref, num, gen, num, gen); +} + +fz_buffer * +pdf_load_raw_renumbered_stream(pdf_document *xref, int num, int gen, int orig_num, int orig_gen) +{ fz_stream *stm; pdf_obj *dict; int len; fz_buffer *buf; + if (num > 0 && num < xref->len && xref->table[num].stm_buf) + return fz_keep_buffer(xref->ctx, xref->table[num].stm_buf); + dict = pdf_load_object(xref, num, gen); /* RJW: "cannot load stream dictionary (%d %d R)", num, gen */ @@ -438,7 +444,7 @@ pdf_load_raw_stream(pdf_document *xref, int num, int gen) pdf_drop_obj(dict); - stm = pdf_open_raw_stream(xref, num, gen); + stm = pdf_open_raw_renumbered_stream(xref, num, gen, orig_num, orig_gen); /* RJW: "cannot open raw stream (%d %d R)", num, gen */ buf = fz_read_all(stm, len); @@ -470,11 +476,17 @@ pdf_guess_filter_length(int len, char *filter) fz_buffer * pdf_load_stream(pdf_document *xref, int num, int gen) { - return pdf_load_image_stream(xref, num, gen, NULL); + return pdf_load_image_stream(xref, num, gen, num, gen, NULL); +} + +fz_buffer * +pdf_load_renumbered_stream(pdf_document *xref, int num, int gen, int orig_num, int orig_gen) +{ + return pdf_load_image_stream(xref, num, gen, orig_num, orig_gen, NULL); } fz_buffer * -pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +pdf_load_image_stream(pdf_document *xref, int num, int gen, int orig_num, int orig_gen, pdf_image_params *params) { fz_context *ctx = xref->ctx; fz_stream *stm = NULL; @@ -496,7 +508,7 @@ pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *pa pdf_drop_obj(dict); - stm = pdf_open_image_stream(xref, num, gen, params); + stm = pdf_open_image_stream(xref, num, gen, orig_num, orig_gen, params); /* RJW: "cannot open stream (%d %d R)", num, gen */ fz_try(ctx) @@ -514,3 +526,49 @@ pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *pa return buf; } + +static fz_stream * +pdf_open_object_array(pdf_document *xref, pdf_obj *list) +{ + int i, n; + fz_context *ctx = xref->ctx; + fz_stream *stm; + + n = pdf_array_len(list); + stm = fz_open_concat(ctx, n, 1); + + fz_var(i); /* Workaround Mac compiler bug */ + for (i = 0; i < n; i++) + { + pdf_obj *obj = pdf_array_get(list, i); + fz_try(ctx) + { + fz_concat_push(stm, pdf_open_stream(xref, pdf_to_num(obj), pdf_to_gen(obj))); + } + fz_catch(ctx) + { + fz_warn(ctx, "cannot load content stream part %d/%d", i + 1, n); + continue; + } + } + + return stm; +} + +fz_stream * +pdf_open_contents_stream(pdf_document *xref, pdf_obj *obj) +{ + fz_context *ctx = xref->ctx; + int num, gen; + + if (pdf_is_array(obj)) + return pdf_open_object_array(xref, obj); + + num = pdf_to_num(obj); + gen = pdf_to_gen(obj); + if (pdf_is_stream(xref, num, gen)) + return pdf_open_image_stream(xref, num, gen, num, gen, NULL); + + fz_warn(ctx, "pdf object stream missing (%d %d R)", num, gen); + return NULL; +} diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c index 6603fc8b..4df46ce3 100644 --- a/pdf/pdf_type3.c +++ b/pdf/pdf_type3.c @@ -2,10 +2,9 @@ #include "mupdf-internal.h" static void -pdf_run_glyph_func(void *doc, void *rdb_, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) +pdf_run_glyph_func(void *doc, void *rdb, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) { - pdf_obj *rdb = (pdf_obj *)rdb_; - pdf_run_glyph(doc, rdb, contents, dev, ctm, gstate); + pdf_run_glyph(doc, (pdf_obj *)rdb, contents, dev, ctm, gstate); } static void diff --git a/pdf/pdf_write.c b/pdf/pdf_write.c new file mode 100644 index 00000000..ed0b8711 --- /dev/null +++ b/pdf/pdf_write.c @@ -0,0 +1,690 @@ +#include "fitz.h" +#include "mupdf-internal.h" + +typedef struct pdf_write_options_s pdf_write_options; + +struct pdf_write_options_s +{ + FILE *out; + int doascii; + int doexpand; + int dogarbage; + char *uselist; + int *ofslist; + int *genlist; + int *renumbermap; + int *revrenumbermap; + int *revgenlist; +}; + +/* + * Garbage collect objects not reachable from the trailer. + */ + +static pdf_obj *sweepref(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj) +{ + int num = pdf_to_num(obj); + int gen = pdf_to_gen(obj); + fz_context *ctx = xref->ctx; + + if (num < 0 || num >= xref->len) + return NULL; + if (opts->uselist[num]) + return NULL; + + opts->uselist[num] = 1; + + /* Bake in /Length in stream objects */ + fz_try(ctx) + { + if (pdf_is_stream(xref, num, gen)) + { + pdf_obj *len = pdf_dict_gets(obj, "Length"); + if (pdf_is_indirect(len)) + { + opts->uselist[pdf_to_num(len)] = 0; + len = pdf_resolve_indirect(len); + pdf_dict_puts(obj, "Length", len); + } + } + } + fz_catch(ctx) + { + /* Leave broken */ + } + + return pdf_resolve_indirect(obj); +} + +static void sweepobj(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj) +{ + int i; + + if (pdf_is_indirect(obj)) + obj = sweepref(xref, opts, obj); + + if (pdf_is_dict(obj)) + { + int n = pdf_dict_len(obj); + for (i = 0; i < n; i++) + sweepobj(xref, opts, pdf_dict_get_val(obj, i)); + } + + else if (pdf_is_array(obj)) + { + int n = pdf_array_len(obj); + for (i = 0; i < n; i++) + sweepobj(xref, opts, pdf_array_get(obj, i)); + } +} + +/* + * Scan for and remove duplicate objects (slow) + */ + +static void removeduplicateobjs(pdf_document *xref, pdf_write_options *opts) +{ + int num, other; + fz_context *ctx = xref->ctx; + + for (num = 1; num < xref->len; num++) + { + /* Only compare an object to objects preceding it */ + for (other = 1; other < num; other++) + { + pdf_obj *a, *b; + int differ, newnum; + + if (num == other || !opts->uselist[num] || !opts->uselist[other]) + continue; + + /* + * Comparing stream objects data contents would take too long. + * + * pdf_is_stream calls pdf_cache_object and ensures + * that the xref table has the objects loaded. + */ + fz_try(ctx) + { + differ = (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0)); + } + fz_catch(ctx) + { + /* Assume different */ + differ = 1; + } + if (differ) + continue; + + a = xref->table[num].obj; + b = xref->table[other].obj; + + a = pdf_resolve_indirect(a); + b = pdf_resolve_indirect(b); + + if (pdf_objcmp(a, b)) + continue; + + /* Keep the lowest numbered object */ + 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 */ + break; + } + } +} + +/* + * 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) +{ + int num, newnum; + + /* + * Update renumbermap in-place, clustering all used + * objects together at low object ids. Objects that + * already should be renumbered will have their new + * object ids be updated to reflect the compaction. + */ + + newnum = 1; + for (num = 1; num < xref->len; 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++; + } + /* 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]]; + } + } +} + +/* + * Update indirect objects according to renumbering established when + * removing duplicate objects and compacting the xref. + */ + +static void renumberobj(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj) +{ + int i; + fz_context *ctx = xref->ctx; + + if (pdf_is_dict(obj)) + { + int n = pdf_dict_len(obj); + for (i = 0; i < n; i++) + { + pdf_obj *key = pdf_dict_get_key(obj, i); + pdf_obj *val = pdf_dict_get_val(obj, i); + if (pdf_is_indirect(val)) + { + val = pdf_new_indirect(ctx, opts->renumbermap[pdf_to_num(val)], 0, xref); + fz_dict_put(obj, key, val); + pdf_drop_obj(val); + } + else + { + renumberobj(xref, opts, val); + } + } + } + + else if (pdf_is_array(obj)) + { + int n = pdf_array_len(obj); + for (i = 0; i < n; i++) + { + pdf_obj *val = pdf_array_get(obj, i); + if (pdf_is_indirect(val)) + { + val = pdf_new_indirect(ctx, opts->renumbermap[pdf_to_num(val)], 0, xref); + pdf_array_put(obj, i, val); + pdf_drop_obj(val); + } + else + { + renumberobj(xref, opts, val); + } + } + } +} + +static void renumberobjs(pdf_document *xref, pdf_write_options *opts) +{ + pdf_xref_entry *oldxref; + int newlen; + int num; + fz_context *ctx = xref->ctx; + + /* Apply renumber map to indirect references in all objects in xref */ + renumberobj(xref, opts, xref->trailer); + for (num = 0; num < xref->len; num++) + { + pdf_obj *obj = xref->table[num].obj; + + if (pdf_is_indirect(obj)) + { + obj = pdf_new_indirect(ctx, opts->renumbermap[pdf_to_num(obj)], 0, xref); + pdf_update_object(xref, num, obj); + pdf_drop_obj(obj); + } + else + { + renumberobj(xref, opts, obj); + } + } + + /* Create new table for the reordered, compacted xref */ + oldxref = xref->table; + xref->table = fz_malloc_array(xref->ctx, xref->len, sizeof(pdf_xref_entry)); + xref->table[0] = oldxref[0]; + + /* Move used objects into the new compacted xref */ + newlen = 0; + for (num = 1; num < xref->len; num++) + { + if (opts->uselist[num]) + { + if (newlen < opts->renumbermap[num]) + newlen = opts->renumbermap[num]; + xref->table[opts->renumbermap[num]] = oldxref[num]; + } + else + { + if (oldxref[num].obj) + pdf_drop_obj(oldxref[num].obj); + } + } + + fz_free(xref->ctx, oldxref); + + /* Update the used objects count in compacted xref */ + xref->len = newlen + 1; + + /* Update list of used objects to fit with compacted xref */ + for (num = 1; num < xref->len; num++) + opts->uselist[num] = 1; +} + +/* + * Make sure we have loaded objects from object streams. + */ + +static void preloadobjstms(pdf_document *xref) +{ + pdf_obj *obj; + int num; + + for (num = 0; num < xref->len; num++) + { + if (xref->table[num].type == 'o') + { + obj = pdf_load_object(xref, num, 0); + pdf_drop_obj(obj); + } + } +} + +/* + * Save streams and objects to the output + */ + +static inline int isbinary(int c) +{ + if (c == '\n' || c == '\r' || c == '\t') + return 0; + return c < 32 || c > 127; +} + +static int isbinarystream(fz_buffer *buf) +{ + int i; + for (i = 0; i < buf->len; i++) + if (isbinary(buf->data[i])) + return 1; + return 0; +} + +static fz_buffer *hexbuf(fz_context *ctx, unsigned char *p, int n) +{ + static const char hex[16] = "0123456789abcdef"; + fz_buffer *buf; + int x = 0; + + buf = fz_new_buffer(ctx, n * 2 + (n / 32) + 2); + + while (n--) + { + buf->data[buf->len++] = hex[*p >> 4]; + buf->data[buf->len++] = hex[*p & 15]; + if (++x == 32) + { + buf->data[buf->len++] = '\n'; + x = 0; + } + p++; + } + + buf->data[buf->len++] = '>'; + buf->data[buf->len++] = '\n'; + + return buf; +} + +static void addhexfilter(pdf_document *xref, pdf_obj *dict) +{ + pdf_obj *f, *dp, *newf, *newdp; + pdf_obj *ahx, *nullobj; + fz_context *ctx = xref->ctx; + + ahx = fz_new_name(ctx, "ASCIIHexDecode"); + nullobj = pdf_new_null(ctx); + newf = newdp = NULL; + + f = pdf_dict_gets(dict, "Filter"); + dp = pdf_dict_gets(dict, "DecodeParms"); + + if (pdf_is_name(f)) + { + newf = pdf_new_array(ctx, 2); + pdf_array_push(newf, ahx); + pdf_array_push(newf, f); + f = newf; + if (pdf_is_dict(dp)) + { + newdp = pdf_new_array(ctx, 2); + pdf_array_push(newdp, nullobj); + pdf_array_push(newdp, dp); + dp = newdp; + } + } + else if (pdf_is_array(f)) + { + pdf_array_insert(f, ahx); + if (pdf_is_array(dp)) + pdf_array_insert(dp, nullobj); + } + else + f = ahx; + + pdf_dict_puts(dict, "Filter", f); + if (dp) + pdf_dict_puts(dict, "DecodeParms", dp); + + pdf_drop_obj(ahx); + pdf_drop_obj(nullobj); + if (newf) + pdf_drop_obj(newf); + if (newdp) + pdf_drop_obj(newdp); +} + +static void copystream(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj, int num, int gen) +{ + 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_renumbered_stream(xref, num, gen, orig_num, orig_gen); + + if (opts->doascii && isbinarystream(buf)) + { + tmp = hexbuf(ctx, buf->data, buf->len); + fz_drop_buffer(ctx, buf); + buf = tmp; + + addhexfilter(xref, obj); + + newlen = pdf_new_int(ctx, buf->len); + pdf_dict_puts(obj, "Length", newlen); + pdf_drop_obj(newlen); + } + + fprintf(opts->out, "%d %d obj\n", num, gen); + pdf_fprint_obj(opts->out, obj, opts->doexpand == 0); + fprintf(opts->out, "stream\n"); + fwrite(buf->data, 1, buf->len, opts->out); + fprintf(opts->out, "endstream\nendobj\n\n"); + + fz_drop_buffer(ctx, buf); +} + +static void expandstream(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj, int num, int gen) +{ + 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_renumbered_stream(xref, num, gen, orig_num, orig_gen); + + pdf_dict_dels(obj, "Filter"); + pdf_dict_dels(obj, "DecodeParms"); + + if (opts->doascii && isbinarystream(buf)) + { + tmp = hexbuf(ctx, buf->data, buf->len); + fz_drop_buffer(ctx, buf); + buf = tmp; + + addhexfilter(xref, obj); + } + + newlen = pdf_new_int(ctx, buf->len); + pdf_dict_puts(obj, "Length", newlen); + pdf_drop_obj(newlen); + + fprintf(opts->out, "%d %d obj\n", num, gen); + pdf_fprint_obj(opts->out, obj, opts->doexpand == 0); + fprintf(opts->out, "stream\n"); + fwrite(buf->data, 1, buf->len, opts->out); + fprintf(opts->out, "endstream\nendobj\n\n"); + + fz_drop_buffer(ctx, buf); +} + +static void writeobject(pdf_document *xref, pdf_write_options *opts, int num, int gen) +{ + pdf_obj *obj; + pdf_obj *type; + fz_context *ctx = xref->ctx; + + obj = pdf_load_object(xref, num, gen); + + /* skip ObjStm and XRef objects */ + if (pdf_is_dict(obj)) + { + type = pdf_dict_gets(obj, "Type"); + if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "ObjStm")) + { + opts->uselist[num] = 0; + pdf_drop_obj(obj); + return; + } + if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "XRef")) + { + opts->uselist[num] = 0; + pdf_drop_obj(obj); + return; + } + } + + if (!pdf_is_stream(xref, num, gen)) + { + fprintf(opts->out, "%d %d obj\n", num, gen); + pdf_fprint_obj(opts->out, obj, opts->doexpand == 0); + fprintf(opts->out, "endobj\n\n"); + } + else + { + int dontexpand = 0; + if (opts->doexpand != 0 && opts->doexpand != fz_expand_all) + { + pdf_obj *o; + + if ((o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "XObject")) && + (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Image"))) + dontexpand = !(opts->doexpand & fz_expand_images); + if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "Font")) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "FontDescriptor")) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if ((o = pdf_dict_gets(obj, "Length1")) != NULL) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if ((o = pdf_dict_gets(obj, "Length2")) != NULL) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if ((o = pdf_dict_gets(obj, "Length3")) != NULL) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Type1C")) + dontexpand = !(opts->doexpand & fz_expand_fonts); + if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "CIDFontType0C")) + dontexpand = !(opts->doexpand & fz_expand_fonts); + } + if (opts->doexpand && !dontexpand && !pdf_is_jpx_image(ctx, obj)) + expandstream(xref, opts, obj, num, gen); + else + copystream(xref, opts, obj, num, gen); + } + + pdf_drop_obj(obj); +} + +static void writexref(pdf_document *xref, pdf_write_options *opts) +{ + pdf_obj *trailer; + pdf_obj *obj; + int startxref; + int num; + fz_context *ctx = xref->ctx; + + startxref = ftell(opts->out); + + fprintf(opts->out, "xref\n0 %d\n", xref->len); + for (num = 0; num < xref->len; num++) + { + if (opts->uselist[num]) + fprintf(opts->out, "%010d %05d n \n", opts->ofslist[num], opts->genlist[num]); + else + fprintf(opts->out, "%010d %05d f \n", opts->ofslist[num], opts->genlist[num]); + } + fprintf(opts->out, "\n"); + + trailer = pdf_new_dict(ctx, 5); + + obj = pdf_new_int(ctx, xref->len); + pdf_dict_puts(trailer, "Size", obj); + pdf_drop_obj(obj); + + obj = pdf_dict_gets(xref->trailer, "Info"); + if (obj) + pdf_dict_puts(trailer, "Info", obj); + + obj = pdf_dict_gets(xref->trailer, "Root"); + if (obj) + pdf_dict_puts(trailer, "Root", obj); + + obj = pdf_dict_gets(xref->trailer, "ID"); + if (obj) + pdf_dict_puts(trailer, "ID", obj); + + fprintf(opts->out, "trailer\n"); + pdf_fprint_obj(opts->out, trailer, opts->doexpand == 0); + fprintf(opts->out, "\n"); + + pdf_drop_obj(trailer); + + fprintf(opts->out, "startxref\n%d\n%%%%EOF\n", startxref); +} + +void pdf_write_document(pdf_document *xref, char *filename, fz_write_options *fz_opts) +{ + int lastfree; + int num; + pdf_write_options opts = { 0 }; + fz_context *ctx; + + if (!xref || !fz_opts) + return; + + ctx = xref->ctx; + + opts.out = fopen(filename, "wb"); + if (!opts.out) + fz_throw(ctx, "cannot open output file '%s'", filename); + + fz_try(ctx) + { + opts.doexpand = fz_opts ? fz_opts->doexpand : 0; + opts.dogarbage = fz_opts ? fz_opts->dogarbage : 0; + opts.doascii = fz_opts ? fz_opts->doascii: 0; + opts.uselist = fz_malloc_array(ctx, xref->len + 1, sizeof(char)); + 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"); + + for (num = 0; num < xref->len; num++) + { + 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 */ + preloadobjstms(xref); + + /* Sweep & mark objects from the trailer */ + if (opts.dogarbage >= 1) + sweepobj(xref, &opts, xref->trailer); + + /* Coalesce and renumber duplicate objects */ + if (opts.dogarbage >= 3) + removeduplicateobjs(xref, &opts); + + /* Compact xref by renumbering and removing unused objects */ + if (opts.dogarbage >= 2) + compactxref(xref, &opts); + + /* Make renumbering affect all indirect references and update xref */ + if (opts.dogarbage >= 2) + renumberobjs(xref, &opts); + + for (num = 0; num < xref->len; num++) + { + if (xref->table[num].type == 'f') + opts.genlist[num] = xref->table[num].gen; + if (xref->table[num].type == 'n') + opts.genlist[num] = xref->table[num].gen; + if (xref->table[num].type == 'o') + opts.genlist[num] = 0; + + if (opts.dogarbage && !opts.uselist[num]) + continue; + + if (xref->table[num].type == 'n' || xref->table[num].type == 'o') + { + opts.uselist[num] = 1; + opts.ofslist[num] = ftell(opts.out); + writeobject(xref, &opts, num, opts.genlist[num]); + } + } + + /* Construct linked list of free object slots */ + lastfree = 0; + for (num = 0; num < xref->len; num++) + { + if (!opts.uselist[num]) + { + opts.genlist[num]++; + opts.ofslist[lastfree] = num; + lastfree = num; + } + } + + writexref(xref, &opts); + } + fz_always(ctx) + { + fz_free(ctx, opts.uselist); + 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) + { + fz_rethrow(ctx); + } +} diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c index 175f84b5..88ab5a01 100644 --- a/pdf/pdf_xobject.c +++ b/pdf/pdf_xobject.c @@ -23,7 +23,7 @@ pdf_free_xobject_imp(fz_context *ctx, fz_storable *xobj_) if (xobj->resources) pdf_drop_obj(xobj->resources); if (xobj->contents) - fz_drop_buffer(ctx, xobj->contents); + pdf_drop_obj(xobj->contents); pdf_drop_obj(xobj->me); fz_free(ctx, xobj); } @@ -33,7 +33,7 @@ pdf_xobject_size(pdf_xobject *xobj) { if (xobj == NULL) return 0; - return sizeof(*xobj) + (xobj->colorspace ? xobj->colorspace->size : 0) + (xobj->contents ? xobj->contents->len : 0); + return sizeof(*xobj) + (xobj->colorspace ? xobj->colorspace->size : 0); } pdf_xobject * @@ -98,7 +98,7 @@ pdf_load_xobject(pdf_document *xref, pdf_obj *dict) fz_try(ctx) { - form->contents = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); + form->contents = pdf_keep_obj(dict); } fz_catch(ctx) { @@ -114,6 +114,7 @@ pdf_load_xobject(pdf_document *xref, pdf_obj *dict) pdf_obj * pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat) { + int idict_num; pdf_obj *idict = NULL; pdf_obj *dict = NULL; pdf_xobject *form = NULL; @@ -195,12 +196,15 @@ pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat) form->resources = res; res = NULL; - idict = pdf_new_stream_indirection(xref, dict); + idict_num = pdf_create_object(xref); + pdf_update_object(xref, idict_num, dict); + idict = pdf_new_indirect(ctx, idict_num, 0, xref); pdf_drop_obj(dict); dict = NULL; pdf_store_item(ctx, idict, form, pdf_xobject_size(form)); + form->contents = pdf_keep_obj(idict); form->me = pdf_keep_obj(idict); pdf_drop_xobject(ctx, form); @@ -220,8 +224,8 @@ pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat) return idict; } -void pdf_xobject_set_contents(fz_context *ctx, pdf_xobject *form, fz_buffer *buffer) +void pdf_xobject_set_contents(pdf_document *xref, pdf_xobject *form, fz_buffer *buffer) { - fz_drop_buffer(ctx, form->contents); - form->contents = fz_keep_buffer(ctx, buffer); + pdf_dict_dels(form->contents, "Filter"); + pdf_update_stream(xref, pdf_to_num(form->contents), buffer); } diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c index cd15051c..ea99d3c2 100644 --- a/pdf/pdf_xref.c +++ b/pdf/pdf_xref.c @@ -173,6 +173,7 @@ pdf_resize_xref(pdf_document *xref, int newlen) xref->table[i].ofs = 0; xref->table[i].gen = 0; xref->table[i].stm_ofs = 0; + xref->table[i].stm_buf = NULL; xref->table[i].obj = NULL; } xref->len = newlen; @@ -293,8 +294,7 @@ pdf_read_new_xref_section(pdf_document *xref, fz_stream *stm, int i0, int i1, in } } -/* Entered with file locked. Drops the lock in the middle, but then picks - * it up again before exiting. */ +/* Entered with file locked, remains locked throughout. */ static pdf_obj * pdf_read_new_xref(pdf_document *xref, pdf_lexbuf *buf) { @@ -321,7 +321,6 @@ pdf_read_new_xref(pdf_document *xref, pdf_lexbuf *buf) fz_try(ctx) { - fz_unlock(ctx, FZ_LOCK_FILE); obj = pdf_dict_gets(trailer, "Size"); if (!obj) fz_throw(ctx, "xref stream missing Size entry (%d %d R)", num, gen); @@ -371,7 +370,6 @@ pdf_read_new_xref(pdf_document *xref, pdf_lexbuf *buf) pdf_drop_obj(index); fz_rethrow(ctx); } - fz_lock(ctx, FZ_LOCK_FILE); return trailer; } @@ -410,13 +408,13 @@ static void pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf) { pdf_obj *trailer = NULL; - pdf_obj *xrefstm = NULL; - pdf_obj *prev = NULL; fz_context *ctx = xref->ctx; + int xrefstmofs = 0; + int prevofs = 0; fz_var(trailer); - fz_var(xrefstm); - fz_var(prev); + fz_var(xrefstmofs); + fz_var(prevofs); fz_try(ctx) { @@ -425,20 +423,21 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf) trailer = pdf_read_xref(xref, ofs, buf); /* FIXME: do we overwrite free entries properly? */ - xrefstm = pdf_dict_gets(trailer, "XRefStm"); - prev = pdf_dict_gets(trailer, "Prev"); + xrefstmofs = pdf_to_int(pdf_dict_gets(trailer, "XRefStm")); + prevofs = pdf_to_int(pdf_dict_gets(trailer, "Prev")); + /* We only recurse if we have both xrefstm and prev. * Hopefully this happens infrequently. */ - if (xrefstm && prev) - pdf_read_xref_sections(xref, pdf_to_int(xrefstm), buf); - if (prev) - ofs = pdf_to_int(prev); - else if (xrefstm) - ofs = pdf_to_int(xrefstm); + if (xrefstmofs && prevofs) + pdf_read_xref_sections(xref, xrefstmofs, buf); + if (prevofs) + ofs = prevofs; + else if (xrefstmofs) + ofs = xrefstmofs; pdf_drop_obj(trailer); trailer = NULL; } - while (prev || xrefstm); + while (prevofs || xrefstmofs); } fz_catch(ctx) { @@ -449,12 +448,14 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf) /* * load xref tables from pdf + * + * File locked on entry, throughout and on exit. */ static void pdf_load_xref(pdf_document *xref, pdf_lexbuf *buf) { - pdf_obj *size; + int size; int i; fz_context *ctx = xref->ctx; @@ -464,11 +465,11 @@ pdf_load_xref(pdf_document *xref, pdf_lexbuf *buf) pdf_read_trailer(xref, buf); - size = pdf_dict_gets(xref->trailer, "Size"); + size = pdf_to_int(pdf_dict_gets(xref->trailer, "Size")); if (!size) fz_throw(ctx, "trailer missing Size entry"); - pdf_resize_xref(xref, pdf_to_int(size)); + pdf_resize_xref(xref, size); pdf_read_xref_sections(xref, xref->startxref, buf); @@ -660,33 +661,18 @@ pdf_free_ocg(fz_context *ctx, pdf_ocg_descriptor *desc) * If password is not null, try to decrypt. */ -static void pdf_init_document(pdf_document *xref); - -pdf_document * -pdf_open_document_with_stream(fz_stream *file) +static void +pdf_init_document(pdf_document *xref) { - pdf_document *xref; + fz_context *ctx = xref->ctx; pdf_obj *encrypt, *id; pdf_obj *dict = NULL; pdf_obj *obj; pdf_obj *nobj = NULL; int i, repaired = 0; - int locked; - fz_context *ctx = file->ctx; fz_var(dict); fz_var(nobj); - fz_var(locked); - - xref = fz_malloc_struct(ctx, pdf_document); - pdf_init_document(xref); - xref->lexbuf.base.size = PDF_LEXBUF_LARGE; - - xref->file = fz_keep_stream(file); - xref->ctx = ctx; - - fz_lock(ctx, FZ_LOCK_FILE); - locked = 1; fz_try(ctx) { @@ -717,9 +703,6 @@ pdf_open_document_with_stream(fz_stream *file) if (repaired) pdf_repair_xref(xref, &xref->lexbuf.base); - fz_unlock(ctx, FZ_LOCK_FILE); - locked = 0; - encrypt = pdf_dict_gets(xref->trailer, "Encrypt"); id = pdf_dict_gets(xref->trailer, "ID"); if (pdf_is_dict(encrypt)) @@ -778,11 +761,6 @@ pdf_open_document_with_stream(fz_stream *file) } } } - fz_always(ctx) - { - if (locked) - fz_unlock(ctx, FZ_LOCK_FILE); - } fz_catch(ctx) { pdf_drop_obj(dict); @@ -799,8 +777,6 @@ pdf_open_document_with_stream(fz_stream *file) { fz_warn(ctx, "Ignoring Broken Optional Content"); } - - return xref; } void @@ -865,11 +841,12 @@ pdf_print_xref(pdf_document *xref) printf("xref\n0 %d\n", xref->len); for (i = 0; i < xref->len; i++) { - printf("%05d: %010d %05d %c (stm_ofs=%d)\n", i, + printf("%05d: %010d %05d %c (stm_ofs=%d; stm_buf=%p)\n", i, xref->table[i].ofs, xref->table[i].gen, xref->table[i].type ? xref->table[i].type : '-', - xref->table[i].stm_ofs); + xref->table[i].stm_ofs, + xref->table[i].stm_buf); } } @@ -987,7 +964,6 @@ pdf_cache_object(pdf_document *xref, int num, int gen) } else if (x->type == 'n') { - fz_lock(ctx, FZ_LOCK_FILE); fz_seek(xref->file, x->ofs, 0); fz_try(ctx) @@ -997,7 +973,6 @@ pdf_cache_object(pdf_document *xref, int num, int gen) } fz_catch(ctx) { - fz_unlock(ctx, FZ_LOCK_FILE); fz_throw(ctx, "cannot parse object (%d %d R)", num, gen); } @@ -1005,13 +980,11 @@ pdf_cache_object(pdf_document *xref, int num, int gen) { pdf_drop_obj(x->obj); x->obj = NULL; - fz_unlock(ctx, FZ_LOCK_FILE); fz_throw(ctx, "found object (%d %d R) instead of (%d %d R)", rnum, rgen, num, gen); } if (xref->crypt) pdf_crypt_obj(ctx, xref->crypt, x->obj, num, gen); - fz_unlock(ctx, FZ_LOCK_FILE); } else if (x->type == 'o') { @@ -1093,127 +1066,105 @@ pdf_resolve_indirect(pdf_obj *ref) return ref; } -int pdf_count_objects(pdf_document *doc) +int +pdf_count_objects(pdf_document *doc) { return doc->len; } -/* Replace numbered object -- for use by pdfclean and similar tools */ +int +pdf_create_object(pdf_document *xref) +{ + /* TODO: reuse free object slots by properly linking free object chains in the ofs field */ + int num = xref->len; + pdf_resize_xref(xref, num + 1); + xref->table[num].type = 'f'; + xref->table[num].ofs = -1; + xref->table[num].gen = 0; + xref->table[num].stm_ofs = 0; + xref->table[num].stm_buf = NULL; + xref->table[num].obj = NULL; + return num; +} + void -pdf_update_object(pdf_document *xref, int num, int gen, pdf_obj *newobj) +pdf_delete_object(pdf_document *xref, int num) { pdf_xref_entry *x; if (num < 0 || num >= xref->len) { - fz_warn(xref->ctx, "object out of range (%d %d R); xref size %d", num, gen, xref->len); + fz_warn(xref->ctx, "object out of range (%d 0 R); xref size %d", num, xref->len); return; } x = &xref->table[num]; - if (x->obj) - pdf_drop_obj(x->obj); + fz_drop_buffer(xref->ctx, x->stm_buf); + pdf_drop_obj(x->obj); - x->obj = pdf_keep_obj(newobj); - x->type = 'n'; + x->type = 'f'; x->ofs = 0; + x->gen = 0; + x->stm_ofs = 0; + x->stm_buf = NULL; + x->obj = NULL; } -pdf_obj * -pdf_new_stream_indirection(pdf_document *xref, pdf_obj *obj) -{ - int num = xref->len; - pdf_resize_xref(xref, xref->len + 1); - pdf_update_object(xref, num, 0, obj); - /* Set stm_ofs, so that obj is treated as a stream */ - xref->table[num].stm_ofs = 1; - - return pdf_new_indirect(xref->ctx, num, 0, xref); -} - -/* - * Convenience function to open a file then call pdf_open_document_with_stream. - */ - -pdf_document * -pdf_open_document(fz_context *ctx, const char *filename) +void +pdf_update_object(pdf_document *xref, int num, pdf_obj *newobj) { - fz_stream *file = NULL; - pdf_document *xref; + pdf_xref_entry *x; - fz_var(file); - fz_try(ctx) - { - file = fz_open_file(ctx, filename); - xref = pdf_open_document_with_stream(file); - } - fz_catch(ctx) + if (num < 0 || num >= xref->len) { - fz_close(file); - fz_throw(ctx, "cannot load document '%s'", filename); + fz_warn(xref->ctx, "object out of range (%d 0 R); xref size %d", num, xref->len); + return; } - fz_close(file); - return xref; -} - -/* Document interface wrappers */ + x = &xref->table[num]; -static void pdf_close_document_shim(fz_document *doc) -{ - pdf_close_document((pdf_document*)doc); -} + if (x->obj) + pdf_drop_obj(x->obj); -static int pdf_needs_password_shim(fz_document *doc) -{ - return pdf_needs_password((pdf_document*)doc); + x->type = 'n'; + x->ofs = 0; + x->obj = pdf_keep_obj(newobj); } -static int pdf_authenticate_password_shim(fz_document *doc, char *password) +fz_buffer * +pdf_get_stream(pdf_document *xref, int num) { - return pdf_authenticate_password((pdf_document*)doc, password); -} + pdf_xref_entry *x; -static fz_outline *pdf_load_outline_shim(fz_document *doc) -{ - return pdf_load_outline((pdf_document*)doc); -} + if (num < 0 || num >= xref->len) + fz_throw(xref->ctx, "object out of range (%d 0 R); xref size %d", num, xref->len); -static int pdf_count_pages_shim(fz_document *doc) -{ - return pdf_count_pages((pdf_document*)doc); -} + x = &xref->table[num]; -static fz_page *pdf_load_page_shim(fz_document *doc, int number) -{ - return (fz_page*) pdf_load_page((pdf_document*)doc, number); + return x->stm_buf; } -static fz_link *pdf_load_links_shim(fz_document *doc, fz_page *page) +void +pdf_update_stream(pdf_document *xref, int num, fz_buffer *newbuf) { - return pdf_load_links((pdf_document*)doc, (pdf_page*)page); -} + pdf_xref_entry *x; -static fz_rect pdf_bound_page_shim(fz_document *doc, fz_page *page) -{ - return pdf_bound_page((pdf_document*)doc, (pdf_page*)page); -} + if (num < 0 || num >= xref->len) + { + fz_warn(xref->ctx, "object out of range (%d 0 R); xref size %d", num, xref->len); + return; + } -static void pdf_run_page_shim(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie) -{ - pdf_run_page((pdf_document*)doc, (pdf_page*)page, dev, transform, cookie); -} + x = &xref->table[num]; -static void pdf_free_page_shim(fz_document *doc, fz_page *page) -{ - pdf_free_page((pdf_document*)doc, (pdf_page*)page); + fz_drop_buffer(xref->ctx, x->stm_buf); + x->stm_buf = fz_keep_buffer(xref->ctx, newbuf); } -static int pdf_meta(fz_document *doc_, int key, void *ptr, int size) +int +pdf_meta(pdf_document *doc, int key, void *ptr, int size) { - pdf_document *doc = (pdf_document *)doc_; - switch(key) { /* @@ -1295,9 +1246,72 @@ static fz_interactive *pdf_interact_shim(fz_document *doc) return (fz_interactive *)doc; } -static void -pdf_init_document(pdf_document *doc) +/* + Wrappers to implement the fz_document interface for pdf_document. + + The functions are split across two files to allow calls to a + version of the constructor that does not link in the interpreter. + The interpreter references the built-in font and cmap resources + which are quite big. Not linking those into the mubusy binary + saves roughly 6MB of space. +*/ + +static void pdf_close_document_shim(fz_document *doc) { + pdf_close_document((pdf_document*)doc); +} + +static int pdf_needs_password_shim(fz_document *doc) +{ + return pdf_needs_password((pdf_document*)doc); +} + +static int pdf_authenticate_password_shim(fz_document *doc, char *password) +{ + return pdf_authenticate_password((pdf_document*)doc, password); +} + +static fz_outline *pdf_load_outline_shim(fz_document *doc) +{ + return pdf_load_outline((pdf_document*)doc); +} + +static int pdf_count_pages_shim(fz_document *doc) +{ + return pdf_count_pages((pdf_document*)doc); +} + +static fz_page *pdf_load_page_shim(fz_document *doc, int number) +{ + return (fz_page*) pdf_load_page((pdf_document*)doc, number); +} + +static fz_link *pdf_load_links_shim(fz_document *doc, fz_page *page) +{ + return pdf_load_links((pdf_document*)doc, (pdf_page*)page); +} + +static fz_rect pdf_bound_page_shim(fz_document *doc, fz_page *page) +{ + return pdf_bound_page((pdf_document*)doc, (pdf_page*)page); +} + +static void pdf_free_page_shim(fz_document *doc, fz_page *page) +{ + pdf_free_page((pdf_document*)doc, (pdf_page*)page); +} + +static int pdf_meta_shim(fz_document *doc, int key, void *ptr, int size) +{ + return pdf_meta((pdf_document*)doc, key, ptr, size); +} + +static pdf_document * +pdf_new_document(fz_stream *file) +{ + fz_context *ctx = file->ctx; + pdf_document *doc = fz_malloc_struct(ctx, pdf_document); + doc->super.close = pdf_close_document_shim; doc->super.needs_password = pdf_needs_password_shim; doc->super.authenticate_password = pdf_authenticate_password_shim; @@ -1306,8 +1320,47 @@ pdf_init_document(pdf_document *doc) doc->super.load_page = pdf_load_page_shim; doc->super.load_links = pdf_load_links_shim; doc->super.bound_page = pdf_bound_page_shim; - doc->super.run_page = pdf_run_page_shim; + doc->super.run_page = NULL; /* see pdf_xref_aux.c */ doc->super.free_page = pdf_free_page_shim; - doc->super.meta = pdf_meta; + doc->super.meta = pdf_meta_shim; doc->super.interact = pdf_interact_shim; + + doc->lexbuf.base.size = PDF_LEXBUF_LARGE; + doc->file = fz_keep_stream(file); + doc->ctx = ctx; + + return doc; +} + +pdf_document * +pdf_open_document_no_run_with_stream(fz_stream *file) +{ + pdf_document *doc = pdf_new_document(file); + pdf_init_document(doc); + return doc; +} + +pdf_document * +pdf_open_document_no_run(fz_context *ctx, const char *filename) +{ + fz_stream *file = NULL; + pdf_document *doc; + + fz_var(file); + + fz_try(ctx) + { + file = fz_open_file(ctx, filename); + doc = pdf_new_document(file); + pdf_init_document(doc); + } + fz_always(ctx) + { + fz_close(file); + } + fz_catch(ctx) + { + fz_throw(ctx, "cannot load document '%s'", filename); + } + return doc; } diff --git a/pdf/pdf_xref_aux.c b/pdf/pdf_xref_aux.c new file mode 100644 index 00000000..2d760334 --- /dev/null +++ b/pdf/pdf_xref_aux.c @@ -0,0 +1,31 @@ +#include "fitz-internal.h" +#include "mupdf-internal.h" + +/* + These functions have been split out of pdf_xref.c to allow tools + to be linked without pulling in the interpreter. The interpreter + references the built-in font and cmap resources which are quite + big. Not linking those into the tools saves roughly 6MB in the + resulting executables. +*/ + +static void pdf_run_page_shim(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie) +{ + pdf_run_page((pdf_document*)doc, (pdf_page*)page, dev, transform, cookie); +} + +pdf_document * +pdf_open_document_with_stream(fz_stream *file) +{ + pdf_document *doc = pdf_open_document_no_run_with_stream(file); + doc->super.run_page = pdf_run_page_shim; + return doc; +} + +pdf_document * +pdf_open_document(fz_context *ctx, const char *filename) +{ + pdf_document *doc = pdf_open_document_no_run(ctx, filename); + doc->super.run_page = pdf_run_page_shim; + return doc; +} diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c index 57cfe54b..53247339 100644 --- a/scripts/cmapdump.c +++ b/scripts/cmapdump.c @@ -85,7 +85,6 @@ main(int argc, char **argv) clean(name); fi = fz_open_file(ctx, argv[i]); - fz_lock_stream(fi); cmap = pdf_load_cmap(ctx, fi); fz_close(fi); diff --git a/scripts/runtohtml.sh b/scripts/runtohtml.sh new file mode 100644 index 00000000..9b94e22b --- /dev/null +++ b/scripts/runtohtml.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +mkdir -p doc/source +rm doc/source/*.html + +FILES="fitz/*.[ch] draw/*.[ch] pdf/*.[ch] xps/*.[ch] cbz/*.[ch] apps/*.[ch]" + +echo running ctags to make xref +ctags -x $FILES > tags-xref + +for input in $FILES +do + output=doc/source/$(basename $input).html + echo $input $output + python scripts/tohtml.py < $input > $output +done + +rm tags-xref diff --git a/scripts/tohtml.py b/scripts/tohtml.py new file mode 100644 index 00000000..6ad22ecd --- /dev/null +++ b/scripts/tohtml.py @@ -0,0 +1,66 @@ +import sys, os, re + +HEADER="""<head> +<style> +body { background-color:#fffff0; color:black; margin:16pt; } +a { text-decoration:none; color:darkblue; } +a.line { position:relative; padding-top:300px; } +.comment { color:green; font-style:italic; } +.comment a { color:darkgreen; } +</style> +</head> +<body><pre><pre>""" + +FOOTER="""</pre></body>""" + +prefixes = [ 'fz_', 'pdf_', 'xps_', 'cbz_', 'pdfapp_' ] + +def is_public(s): + for prefix in prefixes: + if s.startswith(prefix): + return True + return False + +def load_tags(): + tags = {} + for line in open("tags-xref").readlines(): + ident, type, line, file, text = line.split(None, 4) + if not is_public(ident): + continue + if type == 'function': + tags[ident] = '<a class="function" href="%s#%s">%s</a>' % (os.path.basename(file), line, ident) + if type == 'typedef' or type == 'struct': + tags[ident] = '<a class="typedef" href="%s#%s">%s</a>' % (os.path.basename(file), line, ident) + return tags + +tags = load_tags() + +def quote(s): + return s.replace('&','&').replace('<','<').replace('>','>') + +print HEADER + +N = 1 +for line in sys.stdin.readlines(): + # expand tabs, html-quote special characters and colorize comments + line = line.replace('\t', ' ').rstrip() + line = quote(line) + line = line.replace("/*", '<span class="comment">/*') + line = line.replace("*/", '*/</span>') + + line = re.sub('^#include "([a-z-]*\.h)"', '#include "<a href="\\1">\\1</a>"', line) + + # find identifiers and hyperlink to their definitions + words = re.split("(\W+)", line) + line = "" + for word in words: + if word in tags: + word = tags[word] + line += word + + #print('<a class="line" name="%d">%4d</a> %s' % (N, N, line)) + print('<a class="line" name="%d"></a>%s' % (N, line)) + + N = N + 1 + +print FOOTER diff --git a/win32/libmupdf-v8.vcproj b/win32/libmupdf-v8.vcproj index af20539a..9a7baf54 100644 --- a/win32/libmupdf-v8.vcproj +++ b/win32/libmupdf-v8.vcproj @@ -211,10 +211,6 @@ Name="pdf" > <File - RelativePath="..\pdf\base_object.c" - > - </File> - <File RelativePath="..\pdf\data_encodings.h" > </File> @@ -315,6 +311,10 @@ > </File> <File + RelativePath="..\pdf\pdf_object.c" + > + </File> + <File RelativePath="..\pdf\pdf_outline.c" > </File> @@ -362,6 +362,10 @@ RelativePath="..\pdf\pdf_xref.c" > </File> + <File + RelativePath="..\pdf\pdf_xref_aux.c" + > + </File> </Filter> <Filter Name="fitz" diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj index 2bd67845..a15c8cb0 100644 --- a/win32/libmupdf.vcproj +++ b/win32/libmupdf.vcproj @@ -210,10 +210,6 @@ Name="pdf" > <File - RelativePath="..\pdf\base_object.c" - > - </File> - <File RelativePath="..\pdf\data_encodings.h" > </File> @@ -302,6 +298,10 @@ > </File> <File + RelativePath="..\pdf\pdf_object.c" + > + </File> + <File RelativePath="..\pdf\pdf_outline.c" > </File> @@ -342,6 +342,10 @@ > </File> <File + RelativePath="..\pdf\pdf_write.c" + > + </File> + <File RelativePath="..\pdf\pdf_xobject.c" > </File> @@ -349,6 +353,10 @@ RelativePath="..\pdf\pdf_xref.c" > </File> + <File + RelativePath="..\pdf\pdf_xref_aux.c" + > + </File> </Filter> <Filter Name="fitz" diff --git a/win32/mubusy.vcproj b/win32/mubusy.vcproj index f7d27360..c905681e 100644 --- a/win32/mubusy.vcproj +++ b/win32/mubusy.vcproj @@ -241,23 +241,23 @@ > </File> <File - RelativePath="..\apps\mubusy_draw.c" + RelativePath="..\apps\mupdfclean.c" > </File> <File - RelativePath="..\apps\mubusy_pdfclean.c" + RelativePath="..\apps\mupdfextract.c" > </File> <File - RelativePath="..\apps\mubusy_pdfextract.c" + RelativePath="..\apps\mupdfinfo.c" > </File> <File - RelativePath="..\apps\mubusy_pdfinfo.c" + RelativePath="..\apps\mupdfposter.c" > </File> <File - RelativePath="..\apps\mubusy_pdfshow.c" + RelativePath="..\apps\mupdfshow.c" > </File> </Files> diff --git a/win32/mupdf.sln b/win32/mupdf.sln index c6e03880..ef64e779 100644 --- a/win32/mupdf.sln +++ b/win32/mupdf.sln @@ -3,8 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdf", "mupdf.vcproj", "{E74F29F0-FA43-4ADC-B92C-6AFA08E4A417}" ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} + {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libthirdparty", "libthirdparty.vcproj", "{5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C}" @@ -16,44 +16,23 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmupdf", "libmupdf.vcproj EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mudraw", "mudraw.vcproj", "{0B51171B-B10E-4EAC-8FFA-19226A1828A3}" ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} - {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} {A5053AA7-02E5-4903-B596-04F17AEB1526} = {A5053AA7-02E5-4903-B596-04F17AEB1526} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdfclean", "mupdfclean.vcproj", "{923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}" - ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} - {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdfshow", "mupdfshow.vcproj", "{50644121-C85F-4EE9-9C54-F7D1BDFAE354}" - ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} - {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdfextract", "mupdfextract.vcproj", "{BD4473E7-2DBE-4568-A0FC-38EED70182DC}" - ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} - {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdfinfo", "mupdfinfo.vcproj", "{E7578F65-AA5B-43A3-981A-D3632C2A3C04}" - ProjectSection(ProjectDependencies) = postProject {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mubusy", "mubusy.vcproj", "{00811970-815B-4F64-BC9D-219078B1F3AA}" ProjectSection(ProjectDependencies) = postProject - {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} {5F615F91-DFF8-4F05-BF48-6222B7D86519} = {5F615F91-DFF8-4F05-BF48-6222B7D86519} + {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} = {5EDCF4FD-0291-4FB9-8D96-D58957CA5E3C} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generated", "generated.vcproj", "{A5053AA7-02E5-4903-B596-04F17AEB1526}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmupdf-v8", "libmupdf-v8.vcproj", "{2E5DAFDB-A060-4011-B760-32F6A3A4BC9D}" + ProjectSection(ProjectDependencies) = postProject + {A5053AA7-02E5-4903-B596-04F17AEB1526} = {A5053AA7-02E5-4903-B596-04F17AEB1526} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupdf-v8", "mupdf-v8.vcproj", "{9035A4F3-4219-45A5-985D-FBF4D9609713}" ProjectSection(ProjectDependencies) = postProject @@ -92,30 +71,6 @@ Global {0B51171B-B10E-4EAC-8FFA-19226A1828A3}.Memento|Win32.Build.0 = Memento|Win32 {0B51171B-B10E-4EAC-8FFA-19226A1828A3}.Release|Win32.ActiveCfg = Release|Win32 {0B51171B-B10E-4EAC-8FFA-19226A1828A3}.Release|Win32.Build.0 = Release|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Debug|Win32.ActiveCfg = Debug|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Debug|Win32.Build.0 = Debug|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Memento|Win32.ActiveCfg = Memento|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Memento|Win32.Build.0 = Memento|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Release|Win32.ActiveCfg = Release|Win32 - {923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}.Release|Win32.Build.0 = Release|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Debug|Win32.ActiveCfg = Debug|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Debug|Win32.Build.0 = Debug|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Memento|Win32.ActiveCfg = Memento|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Memento|Win32.Build.0 = Memento|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Release|Win32.ActiveCfg = Release|Win32 - {50644121-C85F-4EE9-9C54-F7D1BDFAE354}.Release|Win32.Build.0 = Release|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Debug|Win32.ActiveCfg = Debug|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Debug|Win32.Build.0 = Debug|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Memento|Win32.ActiveCfg = Memento|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Memento|Win32.Build.0 = Memento|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Release|Win32.ActiveCfg = Release|Win32 - {BD4473E7-2DBE-4568-A0FC-38EED70182DC}.Release|Win32.Build.0 = Release|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Debug|Win32.ActiveCfg = Debug|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Debug|Win32.Build.0 = Debug|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Memento|Win32.ActiveCfg = Memento|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Memento|Win32.Build.0 = Memento|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Release|Win32.ActiveCfg = Release|Win32 - {E7578F65-AA5B-43A3-981A-D3632C2A3C04}.Release|Win32.Build.0 = Release|Win32 {00811970-815B-4F64-BC9D-219078B1F3AA}.Debug|Win32.ActiveCfg = Debug|Win32 {00811970-815B-4F64-BC9D-219078B1F3AA}.Debug|Win32.Build.0 = Debug|Win32 {00811970-815B-4F64-BC9D-219078B1F3AA}.Memento|Win32.ActiveCfg = Memento|Win32 diff --git a/win32/mupdfclean.vcproj b/win32/mupdfclean.vcproj deleted file mode 100644 index db8c8f3c..00000000 --- a/win32/mupdfclean.vcproj +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="mupdfclean" - ProjectGUID="{923D7C3D-A5CD-47F1-9BB3-F716531DCCCE}" - RootNamespace="mupdf" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - WholeProgramOptimization="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="2" - EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\fitz;..\pdf" - RuntimeLibrary="0" - EnableFunctionLevelLinking="true" - WarningLevel="3" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - OptimizeReferences="2" - EnableCOMDATFolding="2" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Memento|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="MEMENTO=1;DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath="..\apps\mupdfclean.c" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/win32/mupdfextract.vcproj b/win32/mupdfextract.vcproj deleted file mode 100644 index 04251c15..00000000 --- a/win32/mupdfextract.vcproj +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="mupdfextract" - ProjectGUID="{BD4473E7-2DBE-4568-A0FC-38EED70182DC}" - RootNamespace="mupdf" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - WholeProgramOptimization="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="2" - EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\fitz;..\pdf" - RuntimeLibrary="0" - EnableFunctionLevelLinking="true" - WarningLevel="3" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - OptimizeReferences="2" - EnableCOMDATFolding="2" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Memento|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="MEMENTO=1;DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath="..\apps\mupdfextract.c" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/win32/mupdfinfo.vcproj b/win32/mupdfinfo.vcproj deleted file mode 100644 index ad8b960b..00000000 --- a/win32/mupdfinfo.vcproj +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="mupdfinfo" - ProjectGUID="{E7578F65-AA5B-43A3-981A-D3632C2A3C04}" - RootNamespace="mupdf" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - WholeProgramOptimization="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="2" - EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\fitz;..\pdf" - RuntimeLibrary="0" - EnableFunctionLevelLinking="true" - WarningLevel="3" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - OptimizeReferences="2" - EnableCOMDATFolding="2" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Memento|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="MEMENTO=1;DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath="..\apps\mupdfinfo.c" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/win32/mupdfshow.vcproj b/win32/mupdfshow.vcproj deleted file mode 100644 index 49a3f2b6..00000000 --- a/win32/mupdfshow.vcproj +++ /dev/null @@ -1,246 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="mupdfshow" - ProjectGUID="{50644121-C85F-4EE9-9C54-F7D1BDFAE354}" - RootNamespace="mupdf" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - WholeProgramOptimization="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="2" - EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\fitz;..\pdf" - RuntimeLibrary="0" - EnableFunctionLevelLinking="true" - WarningLevel="3" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - OptimizeReferences="2" - EnableCOMDATFolding="2" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Memento|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)\$(ProjectName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\fitz;..\pdf" - PreprocessorDefinitions="MEMENTO=1;DEBUG=1" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - GenerateDebugInformation="true" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCWebDeploymentTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath="..\apps\mupdfshow.c" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/xps/xps_zip.c b/xps/xps_zip.c index ff43abf2..bb6857ee 100644 --- a/xps/xps_zip.c +++ b/xps/xps_zip.c @@ -108,13 +108,11 @@ xps_read_zip_entry(xps_document *doc, xps_entry *ent, unsigned char *outbuf) int code; fz_context *ctx = doc->ctx; - fz_lock(ctx, FZ_LOCK_FILE); fz_seek(doc->file, ent->offset, 0); sig = getlong(doc->file); if (sig != ZIP_LOCAL_FILE_SIG) { - fz_unlock(ctx, FZ_LOCK_FILE); fz_throw(doc->ctx, "wrong zip local file signature (0x%x)", sig); } @@ -137,7 +135,7 @@ xps_read_zip_entry(xps_document *doc, xps_entry *ent, unsigned char *outbuf) } else if (method == 8) { - inbuf = fz_malloc(doc->ctx, ent->csize); + inbuf = fz_malloc(ctx, ent->csize); fz_read(doc->file, inbuf, ent->csize); @@ -153,34 +151,29 @@ xps_read_zip_entry(xps_document *doc, xps_entry *ent, unsigned char *outbuf) code = inflateInit2(&stream, -15); if (code != Z_OK) { - fz_unlock(ctx, FZ_LOCK_FILE); - fz_free(doc->ctx, inbuf); - fz_throw(doc->ctx, "zlib inflateInit2 error: %s", stream.msg); + fz_free(ctx, inbuf); + fz_throw(ctx, "zlib inflateInit2 error: %s", stream.msg); } code = inflate(&stream, Z_FINISH); if (code != Z_STREAM_END) { inflateEnd(&stream); - fz_unlock(ctx, FZ_LOCK_FILE); - fz_free(doc->ctx, inbuf); - fz_throw(doc->ctx, "zlib inflate error: %s", stream.msg); + fz_free(ctx, inbuf); + fz_throw(ctx, "zlib inflate error: %s", stream.msg); } code = inflateEnd(&stream); if (code != Z_OK) { - fz_unlock(ctx, FZ_LOCK_FILE); - fz_free(doc->ctx, inbuf); - fz_throw(doc->ctx, "zlib inflateEnd error: %s", stream.msg); + fz_free(ctx, inbuf); + fz_throw(ctx, "zlib inflateEnd error: %s", stream.msg); } - fz_free(doc->ctx, inbuf); + fz_free(ctx, inbuf); } else { - fz_unlock(ctx, FZ_LOCK_FILE); - fz_throw(doc->ctx, "unknown compression method (%d)", method); + fz_throw(ctx, "unknown compression method (%d)", method); } - fz_unlock(ctx, FZ_LOCK_FILE); } /* @@ -306,7 +299,6 @@ xps_find_and_read_zip_dir(xps_document *doc) int i, n; fz_context *ctx = doc->ctx; - fz_lock(ctx, FZ_LOCK_FILE); fz_seek(doc->file, 0, SEEK_END); file_size = fz_tell(doc->file); @@ -322,7 +314,6 @@ xps_find_and_read_zip_dir(xps_document *doc) if (!memcmp(buf + i, "PK\5\6", 4)) { xps_read_zip_dir(doc, file_size - back + i); - fz_unlock(ctx, FZ_LOCK_FILE); return; } } @@ -330,8 +321,7 @@ xps_find_and_read_zip_dir(xps_document *doc) back += sizeof buf - 4; } - fz_unlock(ctx, FZ_LOCK_FILE); - fz_throw(doc->ctx, "cannot find end of central directory"); + fz_throw(ctx, "cannot find end of central directory"); } /* |