summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc')
-rw-r--r--Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc328
1 files changed, 201 insertions, 127 deletions
diff --git a/Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc b/Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc
index 655fdd8842e..8c112d4261b 100644
--- a/Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc
+++ b/Build/source/texk/web2c/luatexdir/image/pdftoepdf.cc
@@ -19,12 +19,13 @@
with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
static const char _svn_version[] =
- "$Id: pdftoepdf.cc 3606 2010-04-10 12:58:25Z taco $ "
- "$URL: http://foundry.supelec.fr/svn/luatex/branches/0.60.x/source/texk/web2c/luatexdir/image/pdftoepdf.cc $";
+ "$Id: pdftoepdf.cc 4136 2011-04-11 22:06:50Z hhenkel $ "
+ "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.66.0/source/texk/web2c/luatexdir/image/pdftoepdf.cc $";
-#include "epdf.h"
+// define DEBUG
-#define one_hundred_bp 6578176 // one_hundred_bp = 7227 * 65536 / 72
+#include "epdf.h"
+#define HAVE_GETPDFMAJORVERSION 1
// This file is mostly C and not very much C++; it's just used to interface
// the functions of xpdf, which happens to be written in C++.
@@ -62,41 +63,121 @@ static PdfDocument *findPdfDocument(char *file_path)
return pdf_doc;
}
-// Returns pointer to PdfDocument structure for PDF file.
-// Creates a new structure if it doesn't exist yet.
+#define PDF_CHECKSUM_SIZE 32
-char *get_file_checksum(char *a);
+static char *get_file_checksum(char *a, file_error_mode fe)
+{
+ struct stat finfo;
+ char *ck = NULL;
+ if (stat(a, &finfo) == 0) {
+ off_t size = finfo.st_size;
+ time_t mtime = finfo.st_mtime;
+ ck = (char *) malloc(PDF_CHECKSUM_SIZE);
+ if (ck == NULL)
+ pdftex_fail("PDF inclusion: out of memory while processing '%s'",
+ a);
+ snprintf(ck, PDF_CHECKSUM_SIZE, "%llu_%llu", (unsigned long long) size,
+ (unsigned long long) mtime);
+ } else {
+ switch (fe) {
+ case FE_FAIL:
+ pdftex_fail("PDF inclusion: could not stat() file '%s'", a);
+ break;
+ case FE_RETURN_NULL:
+ if (ck != NULL)
+ free(ck);
+ ck = NULL;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return ck;
+}
+
+// Returns pointer to PdfDocument structure for PDF file.
+// Creates a new PdfDocument structure if it doesn't exist yet.
+// When fe = FE_RETURN_NULL, the function returns NULL in error case.
-PdfDocument *refPdfDocument(char *file_path)
+PdfDocument *refPdfDocument(char *file_path, file_error_mode fe)
{
- PdfDocument *pdf_doc = findPdfDocument(file_path);
- if (pdf_doc == NULL) {
- if (PdfDocumentTree == NULL)
- PdfDocumentTree =
- avl_create(CompPdfDocument, NULL, &avl_xallocator);
+ char *checksum;
+ PdfDocument *pdf_doc;
+ PDFDoc *doc = NULL;
+ GooString *docName = NULL;
+ int new_flag = 0;
+ if ((checksum = get_file_checksum(file_path, fe)) == NULL) {
+ assert(fe == FE_RETURN_NULL);
+ return (PdfDocument *) NULL;
+ }
+ assert(checksum != NULL);
+ if ((pdf_doc = findPdfDocument(file_path)) == NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "\nDEBUG: New PdfDocument %s\n", file_path);
+#endif
+ new_flag = 1;
pdf_doc = new PdfDocument;
pdf_doc->file_path = xstrdup(file_path);
- pdf_doc->checksum = get_file_checksum(file_path);
- void **aa = avl_probe(PdfDocumentTree, pdf_doc);
- assert(aa != NULL);
- pdf_doc->ObjMapTree = NULL;
+ pdf_doc->checksum = checksum;
pdf_doc->doc = NULL;
- }
- if (pdf_doc->doc == NULL) {
- GString *docName = new GString(pdf_doc->file_path);
- pdf_doc->doc = new PDFDoc(docName); // takes ownership of docName
- if (!pdf_doc->doc->isOk() || !pdf_doc->doc->okToPrint())
- pdftex_fail("xpdf: reading PDF image failed");
pdf_doc->inObjList = NULL;
+ pdf_doc->ObjMapTree = NULL;
pdf_doc->occurences = 0; // 0 = unreferenced
+ pdf_doc->pc = 0;
+ } else {
+#ifdef DEBUG
+ fprintf(stderr, "\nDEBUG: Found PdfDocument %s (%d)\n",
+ pdf_doc->file_path, pdf_doc->occurences);
+#endif
+ assert(pdf_doc->checksum != NULL);
+ if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
+ pdftex_fail("PDF inclusion: file has changed '%s'", file_path);
+ }
+ free(checksum);
}
+ assert(pdf_doc != NULL);
+ if (pdf_doc->doc == NULL) {
#ifdef DEBUG
- fprintf(stderr, "\nluatex Debug: Creating %s (%d)\n",
- pdf_doc->file_path, pdf_doc->occurences);
+ fprintf(stderr, "\nDEBUG: New PDFDoc %s (%d)\n",
+ pdf_doc->file_path, pdf_doc->occurences);
#endif
+ docName = new GooString(file_path);
+ doc = new PDFDoc(docName); // takes ownership of docName
+ pdf_doc->pc++;
+
+ if (!doc->isOk() || !doc->okToPrint()) {
+ switch (fe) {
+ case FE_FAIL:
+ pdftex_fail("xpdf: reading PDF image failed");
+ break;
+ case FE_RETURN_NULL:
+ delete doc;
+ // delete docName;
+ if (new_flag == 1) {
+ if (pdf_doc->file_path != NULL)
+ free(pdf_doc->file_path);
+ if (pdf_doc->checksum != NULL)
+ free(pdf_doc->checksum);
+ delete pdf_doc;
+ }
+ return (PdfDocument *) NULL;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ pdf_doc->doc = doc;
+ }
+ // PDF file could be opened without problems, checksum ok.
+ if (PdfDocumentTree == NULL)
+ PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
+ if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
+ void **aa = avl_probe(PdfDocumentTree, pdf_doc);
+ assert(aa != NULL);
+ }
pdf_doc->occurences++;
#ifdef DEBUG
- fprintf(stderr, "\nluatex Debug: Incrementing %s (%d)\n",
+ fprintf(stderr, "\nDEBUG: Incrementing %s (%d)\n",
pdf_doc->file_path, pdf_doc->occurences);
#endif
return pdf_doc;
@@ -249,7 +330,7 @@ static char *convertNumToPDF(double n)
static void copyObject(PDF, PdfDocument *, Object *);
-static void copyString(PDF pdf, GString * string)
+static void copyString(PDF pdf, GooString * string)
{
char *p;
unsigned char c;
@@ -293,13 +374,14 @@ static void copyName(PDF pdf, char *s)
static void copyArray(PDF pdf, PdfDocument * pdf_doc, Array * array)
{
int i, l;
- PdfObject obj1;
+ Object obj1;
pdf_puts(pdf, "[");
for (i = 0, l = array->getLength(); i < l; ++i) {
array->getNF(i, &obj1);
- if (!obj1->isName())
+ if (!obj1.isName())
pdf_puts(pdf, " ");
copyObject(pdf, pdf_doc, &obj1);
+ obj1.free();
}
pdf_puts(pdf, "]");
}
@@ -307,13 +389,14 @@ static void copyArray(PDF pdf, PdfDocument * pdf_doc, Array * array)
static void copyDict(PDF pdf, PdfDocument * pdf_doc, Dict * dict)
{
int i, l;
- PdfObject obj1;
+ Object obj1;
pdf_puts(pdf, "<<");
for (i = 0, l = dict->getLength(); i < l; ++i) {
copyName(pdf, dict->getKey(i));
pdf_puts(pdf, " ");
dict->getValNF(i, &obj1);
copyObject(pdf, pdf_doc, &obj1);
+ obj1.free();
pdf_puts(pdf, "\n");
}
pdf_puts(pdf, ">>");
@@ -392,15 +475,16 @@ static void writeRefs(PDF pdf, PdfDocument * pdf_doc)
{
InObj *r, *n;
XRef *xref;
+ Object obj1;
xref = pdf_doc->doc->getXRef();
for (r = pdf_doc->inObjList; r != NULL;) {
- PdfObject obj1;
xref->fetch(r->ref.num, r->ref.gen, &obj1);
- if (obj1->isStream())
+ if (obj1.isStream())
pdf_begin_obj(pdf, r->num, 0);
else
pdf_begin_obj(pdf, r->num, 2); // \pdfobjcompresslevel = 2 is for this
copyObject(pdf, pdf_doc, &obj1);
+ obj1.free();
pdf_puts(pdf, "\n");
pdf_end_obj(pdf);
n = r->next;
@@ -436,26 +520,6 @@ static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
return page->getMediaBox(); // to make the compiler happy
}
-#define PDF_CHECKSUM_SIZE 32
-char *get_file_checksum(char *a)
-{
- struct stat finfo;
- char *ck = NULL;
- if (stat(a, &finfo) == 0) {
- off_t size = finfo.st_size;
- time_t mtime = finfo.st_mtime;
- ck = (char *) malloc(PDF_CHECKSUM_SIZE);
- if (ck == NULL)
- pdftex_fail("PDF inclusion: out of memory while processing '%s'",
- a);
- snprintf(ck, PDF_CHECKSUM_SIZE, "%llu_%llu", (unsigned long long) size,
- (unsigned long long) mtime);
- } else {
- pdftex_fail("PDF inclusion: could not stat() file '%s'", a);
- }
- return ck;
-}
-
// Reads various information about the PDF and sets it up for later inclusion.
// This will fail if the PDF version of the PDF is higher than
// minor_pdf_version_wanted or page_name is given and can not be found.
@@ -469,7 +533,6 @@ read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
PdfDocument *pdf_doc;
Page *page;
int rotate;
- char *checksum;
PDFRectangle *pagebox;
#ifdef HAVE_GETPDFMAJORVERSION
int pdf_major_version_found, pdf_minor_version_found;
@@ -486,15 +549,8 @@ read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
globalParams->setErrQuiet(gFalse);
isInit = gTrue;
}
- // calculate a checksum string
- checksum = get_file_checksum(img_filepath(idict));
// open PDF file
- pdf_doc = refPdfDocument(img_filepath(idict));
- if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
- pdftex_fail("PDF inclusion: file has changed '%s'",
- img_filename(idict));
- }
- free(checksum);
+ pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
// check PDF version
// this works only for PDF 1.x -- but since any versions of PDF newer
// than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
@@ -503,13 +559,15 @@ read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
if ((pdf_major_version_found > 1)
- || (pdf_minor_version_found > minor_pdf_version_wanted)) {
+ || (pdf_minor_version_found > minor_pdf_version_wanted)) {
const char *msg =
"PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
if (pdf_inclusion_errorlevel > 0) {
- pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
+ pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found,
+ minor_pdf_version_wanted);
} else {
- pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
+ pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found,
+ minor_pdf_version_wanted);
}
}
#else
@@ -528,7 +586,7 @@ read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
img_totalpages(idict) = pdf_doc->doc->getCatalog()->getNumPages();
if (img_pagename(idict)) {
// get page by name
- GString name(img_pagename(idict));
+ GooString name(img_pagename(idict));
LinkDest *link = pdf_doc->doc->findDest(&name);
if (link == NULL || !link->isOk())
pdftex_fail("PDF inclusion: invalid destination <%s>",
@@ -607,38 +665,30 @@ read_pdf_info(image_dict * idict, int minor_pdf_version_wanted,
// Here the included PDF is copied, so most errors that can happen
// during PDF inclusion will arise here.
-static void write_epdf1(PDF pdf, image_dict * idict)
+void write_epdf(PDF pdf, image_dict * idict)
{
PdfDocument *pdf_doc;
Page *page;
Ref *pageref;
Dict *pageDict;
- PdfObject info, contents, obj1, pageObj, dictObj;
+ Object obj1, contents, pageobj, pagesobj1, pagesobj2, *op1, *op2, *optmp;
PDFRectangle *pagebox;
int i, l;
float bbox[4];
- char *checksum;
char s[256];
- char *pagedictkeys[] =
+ const char *pagedictkeys[] =
{ "Group", "LastModified", "Metadata", "PieceInfo", "Resources",
"SeparationInfo", NULL
};
-
assert(idict != NULL);
- // calculate a checksum string
- checksum = get_file_checksum(img_filepath(idict));
+
// open PDF file
- pdf_doc = refPdfDocument(img_filepath(idict));
- if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
- pdftex_fail("PDF inclusion: file has changed '%s'",
- img_filename(idict));
- }
- free(checksum);
+ pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
page = pdf_doc->doc->getCatalog()->getPage(img_pagenum(idict));
pageref = pdf_doc->doc->getCatalog()->getPageRef(img_pagenum(idict));
assert(pageref != NULL); // was checked already in read_pdf_info()
- pdf_doc->doc->getXRef()->fetch(pageref->num, pageref->gen, &pageObj);
- pageDict = pageObj->getDict();
+ pdf_doc->doc->getXRef()->fetch(pageref->num, pageref->gen, &pageobj);
+ pageDict = pageobj.getDict();
// write the Page header
pdf_puts(pdf, "/Type /XObject\n/Subtype /Form\n");
@@ -652,12 +702,13 @@ static void write_epdf1(PDF pdf, image_dict * idict)
strlen(pdf_doc->file_path)));
pdf_printf(pdf, "/%s.PageNumber %i\n", pdfkeyprefix,
(int) img_pagenum(idict));
- pdf_doc->doc->getDocInfoNF(&info);
- if (info->isRef()) {
+ pdf_doc->doc->getDocInfoNF(&obj1);
+ if (obj1.isRef()) {
// the info dict must be indirect (PDF Ref p. 61)
pdf_printf(pdf, "/%s.InfoDict ", pdfkeyprefix);
- pdf_printf(pdf, "%d 0 R\n", addInObj(pdf, pdf_doc, info->getRef()));
+ pdf_printf(pdf, "%d 0 R\n", addInObj(pdf, pdf_doc, obj1.getRef()));
}
+ obj1.free();
if (img_is_bbox(idict)) {
bbox[0] = int2bp(img_bbox(idict)[0]);
bbox[1] = int2bp(img_bbox(idict)[1]);
@@ -678,33 +729,54 @@ static void write_epdf1(PDF pdf, image_dict * idict)
// Now all relevant parts of the Page dictionary are copied:
- // Resources validity check
- pageDict->lookupNF("Resources", &dictObj);
- if (dictObj->isNull()) {
- // Resources can be missing (files without them have been spotted
- // in the wild); in which case the /Resouces of the /Page will be used.
- // "This practice is not recommended".
- pdftex_warn
- ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref.)");
- }
-
// Metadata validity check (as a stream it must be indirect)
- pageDict->lookupNF("Metadata", &dictObj);
- if (!dictObj->isNull() && !dictObj->isRef())
+ pageDict->lookupNF((char *) "Metadata", &obj1);
+ if (!obj1.isNull() && !obj1.isRef())
pdftex_warn("PDF inclusion: /Metadata must be indirect object");
+ obj1.free();
// copy selected items in Page dictionary
for (i = 0; pagedictkeys[i] != NULL; i++) {
- pageDict->lookupNF(pagedictkeys[i], &dictObj);
- if (!dictObj->isNull()) {
+ pageDict->lookupNF((char *) pagedictkeys[i], &obj1);
+ if (!obj1.isNull()) {
pdf_printf(pdf, "/%s ", pagedictkeys[i]);
- copyObject(pdf, pdf_doc, &dictObj); // preserves indirection
+ copyObject(pdf, pdf_doc, &obj1); // preserves indirection
}
+ obj1.free();
+ }
+
+ // If there are no Resources in the Page dict of the embedded page,
+ // try to inherit the Resources from the Pages tree of the embedded
+ // PDF file, climbing up the tree until the Resources are found.
+ // (This fixes a problem with Scribus 1.3.3.14.)
+ pageDict->lookupNF((char *) "Resources", &obj1);
+ if (obj1.isNull()) {
+ op1 = &pagesobj1;
+ op2 = &pagesobj2;
+ pageDict->lookup((char *) "Parent", op1);
+ while (op1->isDict()) {
+ obj1.free();
+ op1->dictLookupNF((char *) "Resources", &obj1);
+ if (!obj1.isNull()) {
+ pdf_puts(pdf, "/Resources ");
+ copyObject(pdf, pdf_doc, &obj1);
+ break;
+ }
+ op1->dictLookup((char *) "Parent", op2);
+ optmp = op1;
+ op1 = op2;
+ op2 = optmp;
+ op2->free();
+ };
+ if (!op1->isDict())
+ pdftex_warn("PDF inclusion: Page /Resources missing.");
+ op1->free();
}
+ obj1.free();
// write the Page contents
page->getContents(&contents);
- if (contents->isStream()) {
+ if (contents.isStream()) {
// Variant A: get stream and recompress under control
// of \pdfcompresslevel
//
@@ -714,37 +786,39 @@ static void write_epdf1(PDF pdf, image_dict * idict)
// Variant B: copy stream without recompressing
//
- contents->streamGetDict()->lookup((char *) "F", &obj1);
- if (!obj1->isNull()) {
+ contents.streamGetDict()->lookup((char *) "F", &obj1);
+ if (!obj1.isNull()) {
pdftex_fail("PDF inclusion: Unsupported external stream");
}
- contents->streamGetDict()->lookup((char *) "Length", &obj1);
- assert(!obj1->isNull());
+ obj1.free();
+ contents.streamGetDict()->lookup((char *) "Length", &obj1);
+ assert(!obj1.isNull());
pdf_puts(pdf, "/Length ");
copyObject(pdf, pdf_doc, &obj1);
+ obj1.free();
pdf_puts(pdf, "\n");
- contents->streamGetDict()->lookup((char *) "Filter", &obj1);
- if (!obj1->isNull()) {
+ contents.streamGetDict()->lookup((char *) "Filter", &obj1);
+ if (!obj1.isNull()) {
pdf_puts(pdf, "/Filter ");
copyObject(pdf, pdf_doc, &obj1);
+ obj1.free();
pdf_puts(pdf, "\n");
- contents->streamGetDict()->lookup((char *) "DecodeParms", &obj1);
- if (!obj1->isNull()) {
+ contents.streamGetDict()->lookup((char *) "DecodeParms", &obj1);
+ if (!obj1.isNull()) {
pdf_puts(pdf, "/DecodeParms ");
copyObject(pdf, pdf_doc, &obj1);
pdf_puts(pdf, "\n");
}
}
+ obj1.free();
pdf_puts(pdf, ">>\nstream\n");
- copyStreamStream(pdf, contents->getStream()->getBaseStream());
+ copyStreamStream(pdf, contents.getStream()->getBaseStream());
pdf_end_stream(pdf);
- } else if (contents->isArray()) {
+ } else if (contents.isArray()) {
pdf_begin_stream(pdf);
- for (i = 0, l = contents->arrayGetLength(); i < l; ++i) {
- PdfObject contentsobj;
- copyStreamStream(pdf,
- (contents->
- arrayGet(i, &contentsobj))->getStream());
+ for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
+ copyStreamStream(pdf, (contents.arrayGet(i, &obj1))->getStream());
+ obj1.free();
if (i < (l - 1)) {
// put a space between streams to be on the safe side (streams
// should have a trailing space here, but one never knows)
@@ -758,14 +832,13 @@ static void write_epdf1(PDF pdf, image_dict * idict)
}
// write out all indirect objects
writeRefs(pdf, pdf_doc);
-}
-
-// this relay function is needed to keep some destructor quiet (???)
-
-void write_epdf(PDF pdf, image_dict * idict)
-{
- write_epdf1(pdf, idict);
+ contents.free();
+ pageobj.free();
+ // unrefPdfDocument() must come after contents.free() and pageobj.free()!
+ // TH: The next line makes repeated pdf inclusion unacceptably slow
+#if 0
unrefPdfDocument(img_filepath(idict));
+#endif
}
//**********************************************************************
@@ -780,8 +853,12 @@ static void deletePdfDocumentPdfDoc(PdfDocument * pdf_doc)
n = r->next;
delete r;
}
+#ifdef DEBUG
+ fprintf(stderr, "\nDEBUG: Deleting PDFDoc %s\n", pdf_doc->file_path);
+#endif
delete pdf_doc->doc;
pdf_doc->doc = NULL;
+ pdf_doc->pc++;
}
static void destroyPdfDocument(void *pa, void * /*pb */ )
@@ -798,16 +875,13 @@ void unrefPdfDocument(char *file_path)
{
PdfDocument *pdf_doc = findPdfDocument(file_path);
assert(pdf_doc != NULL);
- assert(pdf_doc->occurences > 0); // aim for point landing
+ assert(pdf_doc->occurences != 0); // aim for point landing
pdf_doc->occurences--;
#ifdef DEBUG
- fprintf(stderr, "\nluatex Debug: Decrementing %s (%d)\n",
+ fprintf(stderr, "\nDEBUG: Decrementing %s (%d)\n",
pdf_doc->file_path, pdf_doc->occurences);
#endif
if (pdf_doc->occurences == 0) {
-#ifdef DEBUG
- fprintf(stderr, "\nluatex Debug: Deleting %s\n", pdf_doc->file_path);
-#endif
assert(pdf_doc->inObjList == NULL); // should be eaten up already
deletePdfDocumentPdfDoc(pdf_doc);
}
@@ -816,7 +890,7 @@ void unrefPdfDocument(char *file_path)
// Called when PDF embedding system is finalized.
// Now deallocate all remaining PdfDocuments.
-void epdf_check_mem()
+void epdf_free()
{
if (PdfDocumentTree != NULL)
avl_destroy(PdfDocumentTree, destroyPdfDocument);