Browse Source

FOP-2875: add support for non-ascii characters in pdf file attachment names, fix name collisions of attachments

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1863870 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_4
Matthias Reischenbacher 4 years ago
parent
commit
3ad9b01d08

+ 1
- 1
fop-core/src/main/java/org/apache/fop/pdf/PDFAction.java View File

byte[] enc = getDocument().getEncryption().encrypt(buf, this); byte[] enc = getDocument().getEncryption().encrypt(buf, this);
return PDFText.toHex(enc, true); return PDFText.toHex(enc, true);
} else { } else {
return "(" + text + ")";
return PDFText.escapeText(text, false);
} }
} }



+ 6
- 7
fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java View File

} }


//Find filespec reference for the embedded file //Find filespec reference for the embedded file
filename = PDFText.toPDFString(filename, '_');
PDFArray files = embeddedFiles.getNames(); PDFArray files = embeddedFiles.getNames();
PDFReference embeddedFileRef = null;
PDFFileSpec fileSpec = null;
int i = 0; int i = 0;
while (i < files.length()) { while (i < files.length()) {
String name = (String)files.get(i);
i++; i++;
PDFReference ref = (PDFReference)files.get(i); PDFReference ref = (PDFReference)files.get(i);
if (name.equals(filename)) {
embeddedFileRef = ref;
if (ref.getObject() instanceof PDFFileSpec
&& ((PDFFileSpec)ref.getObject()).getUnicodeFilename().equals(filename)) {
fileSpec = (PDFFileSpec)ref.getObject();
break; break;
} }
i++; i++;
} }
if (embeddedFileRef == null) {
if (fileSpec == null) {
throw new IllegalStateException( throw new IllegalStateException(
"No embedded file with name " + filename + " present."); "No embedded file with name " + filename + " present.");
} }
//This finally seems to work: //This finally seems to work:
StringBuffer scriptBuffer = new StringBuffer(); StringBuffer scriptBuffer = new StringBuffer();
scriptBuffer.append("this.exportDataObject({cName:\""); scriptBuffer.append("this.exportDataObject({cName:\"");
scriptBuffer.append(filename);
scriptBuffer.append(fileSpec.getFilename());
scriptBuffer.append("\", nLaunch:2});"); scriptBuffer.append("\", nLaunch:2});");


PDFJavaScriptLaunchAction action = new PDFJavaScriptLaunchAction(scriptBuffer.toString()); PDFJavaScriptLaunchAction action = new PDFJavaScriptLaunchAction(scriptBuffer.toString());

+ 23
- 4
fop-core/src/main/java/org/apache/fop/pdf/PDFFileSpec.java View File

* @param filename the filename represented by this object * @param filename the filename represented by this object
*/ */
public PDFFileSpec(String filename) { public PDFFileSpec(String filename) {
this(filename, filename);
}


/* generic creation of object */
super();
/**
* create a /FileSpec object.
*
* @param filename the filename represented by this object
* @param unicodeFilename the unicode filename represented by this object
*/
public PDFFileSpec(String filename, String unicodeFilename) {
put("Type", new PDFName("Filespec")); put("Type", new PDFName("Filespec"));
put("F", filename); put("F", filename);
put("UF", filename); // for non-ascii filenames, since PDF 1.7, 3.10.2
put("UF", unicodeFilename); // for non-ascii filenames, since PDF 1.7, 3.10.2
} }


private String getFilename() {
/**
* Gets the filename.
* @return filename
*/
public String getFilename() {
return (String)get("F"); return (String)get("F");
} }


/**
* Gets the unicode filename
* @return unicode filename
*/
public String getUnicodeFilename() {
return (String)get("UF");
}

/** /**
* Associates an dictionary with pointers to embedded file streams with this file spec. * Associates an dictionary with pointers to embedded file streams with this file spec.
* @param embeddedFileDict the dictionary with pointers to embedded file streams * @param embeddedFileDict the dictionary with pointers to embedded file streams

+ 1
- 2
fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java View File

return dPartRoot; return dPartRoot;
} }


public void addAF(PDFFileSpec fileSpec, String filename) {
public void addAF(PDFFileSpec fileSpec) {
if (af == null) { if (af == null) {
af = new PDFArray(); af = new PDFArray();
put("AF", af); put("AF", af);
} }
af.add(fileSpec); af.add(fileSpec);
fileSpec.put("UF", filename);
fileSpec.put("AFRelationship", new PDFName("Data")); fileSpec.put("AFRelationship", new PDFName("Data"));
} }
} }

+ 4
- 6
fop-core/src/main/java/org/apache/fop/render/pdf/PDFRenderingUtil.java View File

import org.apache.fop.pdf.PDFPageLabels; import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFReference; import org.apache.fop.pdf.PDFReference;
import org.apache.fop.pdf.PDFSetOCGStateAction; import org.apache.fop.pdf.PDFSetOCGStateAction;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFTransitionAction; import org.apache.fop.pdf.PDFTransitionAction;
import org.apache.fop.pdf.PDFXMode; import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.pdf.Version; import org.apache.fop.pdf.Version;
} }
PDFDictionary dict = new PDFDictionary(); PDFDictionary dict = new PDFDictionary();
dict.put("F", file); dict.put("F", file);
String filename = PDFText.toPDFString(embeddedFile.getFilename(), '_');
PDFFileSpec fileSpec = new PDFFileSpec(filename);
pdfDoc.getRoot().addAF(fileSpec, filename);
PDFFileSpec fileSpec = new PDFFileSpec(embeddedFile.getFilename(), embeddedFile.getUnicodeFilename());
String filename = fileSpec.getFilename();
pdfDoc.getRoot().addAF(fileSpec);
fileSpec.setEmbeddedFile(dict); fileSpec.setEmbeddedFile(dict);
if (embeddedFile.getDesc() != null) { if (embeddedFile.getDesc() != null) {
fileSpec.setDescription(embeddedFile.getDesc()); fileSpec.setDescription(embeddedFile.getDesc());
nameArray = new PDFArray(); nameArray = new PDFArray();
embeddedFiles.setNames(nameArray); embeddedFiles.setNames(nameArray);
} }
String name = PDFText.toPDFString(filename);
nameArray.add(name);
nameArray.add(filename);
nameArray.add(new PDFReference(fileSpec)); nameArray.add(new PDFReference(fileSpec));
} }



+ 21
- 2
fop-core/src/main/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachment.java View File

import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.AttributesImpl;


import org.apache.fop.pdf.PDFText;

/** /**
* This is the pass-through value object for the PDF extension. * This is the pass-through value object for the PDF extension.
*/ */
/** filename attribute */ /** filename attribute */
private String filename; private String filename;


/** unicode filename attribute */
private String unicodeFilename;

/** description attribute (optional) */ /** description attribute (optional) */
private String desc; private String desc;


*/ */
public PDFEmbeddedFileAttachment(String filename, String src, String desc) { public PDFEmbeddedFileAttachment(String filename, String src, String desc) {
super(); super();
this.filename = filename;
this.setFilename(filename);
this.src = src; this.src = src;
this.desc = desc; this.desc = desc;
} }
return filename; return filename;
} }


/**
* Returns the unicode file name.
* @return the file name
*/
public String getUnicodeFilename() {
return unicodeFilename;
}

/** /**
* Sets the file name. * Sets the file name.
* @param name The file name to set. * @param name The file name to set.
*/ */
public void setFilename(String name) { public void setFilename(String name) {
this.filename = name;
if (!PDFText.toPDFString(name).equals(name)) {
// replace with auto generated filename, because non-ascii chars are used.
this.filename = "att" + name.hashCode();
} else {
this.filename = name;
}
this.unicodeFilename = name;
} }


/** /**

+ 47
- 1
fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java View File

Assert.assertTrue(out.toString().contains( Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (filename)\n /UF (filename)\n /AFRelationship /Data")); "<<\n /Type /Filespec\n /F (filename)\n /UF (filename)\n /AFRelationship /Data"));
Assert.assertTrue(out.toString().contains("<<\n/S /JavaScript\n" Assert.assertTrue(out.toString().contains("<<\n/S /JavaScript\n"
+ "/JS (this.exportDataObject({cName:\"filename\", nLaunch:2});)\n>>"));
+ "/JS (this.exportDataObject\\({cName:\"filename\", nLaunch:2}\\);)\n>>"));
}

@Test
public void testAddEmbeddedFileGermanUmlaut() throws IFException {
PDFDocumentHandler docHandler = new PDFDocumentHandler(new IFContext(ua));
docHandler.setFontInfo(new FontInfo());
ByteArrayOutputStream out = new ByteArrayOutputStream();
docHandler.setResult(new StreamResult(out));
docHandler.startDocument();
docHandler.startPage(0, "", "", new Dimension());

String germanAe = "\u00E4";
String unicodeFilename = "t" + germanAe + "st";
PDFEmbeddedFileAttachment fileAtt = new PDFEmbeddedFileAttachment(unicodeFilename,
"src", "desc");
docHandler.handleExtensionObject(fileAtt);
docHandler.getDocumentNavigationHandler().renderLink(new Link(
new URIAction("embedded-file:" + unicodeFilename, false), new Rectangle()));
docHandler.endDocument();
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (" + fileAtt.getFilename() + ")\n /UF "
+ PDFText.escapeText(fileAtt.getUnicodeFilename()) + "\n /AFRelationship /Data"));
Assert.assertTrue(out.toString().contains("<<\n/S /JavaScript\n"
+ "/JS (this.exportDataObject\\({cName:\"" + fileAtt.getFilename() + "\", nLaunch:2}\\);)\n>>"));
}

@Test
public void testAddEmbeddedFileParenthesis() throws IFException {
PDFDocumentHandler docHandler = new PDFDocumentHandler(new IFContext(ua));
docHandler.setFontInfo(new FontInfo());
ByteArrayOutputStream out = new ByteArrayOutputStream();
docHandler.setResult(new StreamResult(out));
docHandler.startDocument();
docHandler.startPage(0, "", "", new Dimension());

String unicodeFilename = "t(st";
PDFEmbeddedFileAttachment fileAtt = new PDFEmbeddedFileAttachment(unicodeFilename,
"src", "desc");
docHandler.handleExtensionObject(fileAtt);
docHandler.getDocumentNavigationHandler().renderLink(new Link(
new URIAction("embedded-file:" + unicodeFilename, false), new Rectangle()));
docHandler.endDocument();
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (t\\(st)\n /UF (t\\(st)\n /AFRelationship /Data"));
Assert.assertTrue(out.toString().contains("<<\n/S /JavaScript\n"
+ "/JS (this.exportDataObject\\({cName:\"t\\(st\", nLaunch:2}\\);)\n>>"));
} }
} }

+ 44
- 0
fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java View File

assertTrue(bos.toString().contains("/Subtype /Type1\n")); assertTrue(bos.toString().contains("/Subtype /Type1\n"));
assertTrue(bos.toString().contains("/Subtype /Type1C")); assertTrue(bos.toString().contains("/Subtype /Type1C"));
} }

@Test
public void testGetExternalAction() {

String germanAe = "\u00E4";
String filename = "test";
String unicodeFilename = "t" + germanAe + "st.pdf";
PDFFileSpec fileSpec = new PDFFileSpec(filename, unicodeFilename);

PDFDocument doc = new PDFDocument("");
doc.registerObject(fileSpec);
PDFNames names = doc.getRoot().getNames();
if (names == null) {
//Add Names if not already present
names = doc.getFactory().makeNames();
doc.getRoot().setNames(names);
}

PDFEmbeddedFiles embeddedFiles = names.getEmbeddedFiles();
if (embeddedFiles == null) {
embeddedFiles = new PDFEmbeddedFiles();
doc.assignObjectNumber(embeddedFiles);
doc.addTrailerObject(embeddedFiles);
names.setEmbeddedFiles(embeddedFiles);
}

PDFArray nameArray = embeddedFiles.getNames();
if (nameArray == null) {
nameArray = new PDFArray();
embeddedFiles.setNames(nameArray);
}
nameArray.add(fileSpec.getFilename());
nameArray.add(new PDFReference(fileSpec));

PDFFactory pdfFactory = new PDFFactory(doc);
String target = "embedded-file:" + unicodeFilename;
PDFJavaScriptLaunchAction pdfAction = (PDFJavaScriptLaunchAction)
pdfFactory.getExternalAction(target, false);

String expectedString = "<<\n/S /JavaScript\n/JS (this.exportDataObject\\({cName:\""
+ fileSpec.getFilename() + "\", nLaunch:2}\\);)\n>>";

assertEquals(expectedString, pdfAction.toPDFString());
}
} }

+ 37
- 0
fop-core/src/test/java/org/apache/fop/pdf/PDFFileSpecTestCase.java View File

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: PDFFactoryTestCase.java 1823552 2018-02-08 12:26:33Z ssteiner $ */
package org.apache.fop.pdf;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class PDFFileSpecTestCase {
@Test
public void testPDFFileSpec() {
String germanAe = "\u00E4";
String filename = "test";
String unicodeFilename = "t" + germanAe + "st";
PDFFileSpec fileSpec = new PDFFileSpec(filename, unicodeFilename);
assertEquals(fileSpec.getUnicodeFilename(), unicodeFilename);
assertEquals(fileSpec.getFilename(), filename);
}
}

+ 5
- 1
fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java View File



package org.apache.fop.pdf; package org.apache.fop.pdf;


import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachmentTest;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;
PDFReferenceTestCase.class, PDFReferenceTestCase.class,
PDFResourcesTestCase.class, PDFResourcesTestCase.class,
VersionTestCase.class, VersionTestCase.class,
VersionControllerTestCase.class
VersionControllerTestCase.class,
PDFRootTestCase.class,
PDFFileSpecTestCase.class,
PDFEmbeddedFileAttachmentTest.class
}) })
public class PDFLibraryTestSuite { public class PDFLibraryTestSuite {
} }

+ 3
- 0
fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java View File

{"examples.html?foo#bar", quote("/URI (examples.html?foo#bar)")}, {"examples.html?foo#bar", quote("/URI (examples.html?foo#bar)")},
{"examples.html", quote("<< /URI (examples.html)")}, {"examples.html", quote("<< /URI (examples.html)")},
{"file:examples.html", quote("<< /Type /Filespec /F (examples.html)")}, {"file:examples.html", quote("<< /Type /Filespec /F (examples.html)")},

// parenthesis
{"simple_report_(version2.pdf", quote("<< /URI (simple_report_\\(version2.pdf)")}
}); });
} }



+ 42
- 0
fop-core/src/test/java/org/apache/fop/pdf/PDFRootTestCase.java View File

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: PDFFactoryTestCase.java 1823552 2018-02-08 12:26:33Z ssteiner $ */
package org.apache.fop.pdf;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class PDFRootTestCase {
@Test
public void testAddAf() {
String germanAe = "\u00E4";
String unicodeFilename = "t" + germanAe + "st.pdf";
PDFFileSpec fileSpec = new PDFFileSpec(unicodeFilename);
String filename = fileSpec.getFilename();
PDFDocument doc = new PDFDocument("");
doc.getRoot().addAF(fileSpec);
assertEquals(filename, fileSpec.getFilename());
assertEquals(unicodeFilename, fileSpec.getUnicodeFilename());
}
}

+ 42
- 0
fop-core/src/test/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachmentTest.java View File

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: PDFRenderingUtil.java 1761019 2016-09-16 10:43:45Z ssteiner $ */
package org.apache.fop.render.pdf.extensions;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class PDFEmbeddedFileAttachmentTest {
@Test
public void testGetFilename() {
String germanAe = "\u00E4";
String unicodeFilename = "t" + germanAe + "st";
String src = "src";
String desc = "desc";
PDFEmbeddedFileAttachment fileAtt = new PDFEmbeddedFileAttachment(unicodeFilename, src, desc);
assertEquals(fileAtt.getUnicodeFilename(), unicodeFilename);
assertFalse(fileAtt.getFilename().contains(germanAe));
assertEquals(fileAtt.getSrc(), src);
assertEquals(fileAtt.getDesc(), desc);
}
}

Loading…
Cancel
Save