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

@@ -41,7 +41,7 @@ public abstract class PDFAction extends PDFObject {
byte[] enc = getDocument().getEncryption().encrypt(buf, this);
return PDFText.toHex(enc, true);
} else {
return "(" + text + ")";
return PDFText.escapeText(text, false);
}
}


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

@@ -686,21 +686,20 @@ public class PDFFactory {
}

//Find filespec reference for the embedded file
filename = PDFText.toPDFString(filename, '_');
PDFArray files = embeddedFiles.getNames();
PDFReference embeddedFileRef = null;
PDFFileSpec fileSpec = null;
int i = 0;
while (i < files.length()) {
String name = (String)files.get(i);
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;
}
i++;
}
if (embeddedFileRef == null) {
if (fileSpec == null) {
throw new IllegalStateException(
"No embedded file with name " + filename + " present.");
}
@@ -716,7 +715,7 @@ public class PDFFactory {
//This finally seems to work:
StringBuffer scriptBuffer = new StringBuffer();
scriptBuffer.append("this.exportDataObject({cName:\"");
scriptBuffer.append(filename);
scriptBuffer.append(fileSpec.getFilename());
scriptBuffer.append("\", nLaunch:2});");

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

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

@@ -30,18 +30,37 @@ public class PDFFileSpec extends PDFDictionary {
* @param filename the filename represented by this object
*/
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("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");
}

/**
* 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.
* @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

@@ -334,13 +334,12 @@ public class PDFRoot extends PDFDictionary {
return dPartRoot;
}

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

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

@@ -73,7 +73,6 @@ import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFReference;
import org.apache.fop.pdf.PDFSetOCGStateAction;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFTransitionAction;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.pdf.Version;
@@ -677,9 +676,9 @@ class PDFRenderingUtil {
}
PDFDictionary dict = new PDFDictionary();
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);
if (embeddedFile.getDesc() != null) {
fileSpec.setDescription(embeddedFile.getDesc());
@@ -701,8 +700,7 @@ class PDFRenderingUtil {
nameArray = new PDFArray();
embeddedFiles.setNames(nameArray);
}
String name = PDFText.toPDFString(filename);
nameArray.add(name);
nameArray.add(filename);
nameArray.add(new PDFReference(fileSpec));
}


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

@@ -23,6 +23,8 @@ import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.pdf.PDFText;

/**
* This is the pass-through value object for the PDF extension.
*/
@@ -45,6 +47,9 @@ public class PDFEmbeddedFileAttachment extends PDFExtensionAttachment {
/** filename attribute */
private String filename;

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

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

@@ -66,7 +71,7 @@ public class PDFEmbeddedFileAttachment extends PDFExtensionAttachment {
*/
public PDFEmbeddedFileAttachment(String filename, String src, String desc) {
super();
this.filename = filename;
this.setFilename(filename);
this.src = src;
this.desc = desc;
}
@@ -79,12 +84,26 @@ public class PDFEmbeddedFileAttachment extends PDFExtensionAttachment {
return filename;
}

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

/**
* Sets the file name.
* @param name The file name to set.
*/
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

@@ -58,6 +58,52 @@ public class PDFAttachmentTestCase {
Assert.assertTrue(out.toString().contains(
"<<\n /Type /Filespec\n /F (filename)\n /UF (filename)\n /AFRelationship /Data"));
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

@@ -167,4 +167,48 @@ public class PDFFactoryTestCase {
assertTrue(bos.toString().contains("/Subtype /Type1\n"));
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

@@ -0,0 +1,37 @@
/*
* 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

@@ -19,6 +19,7 @@

package org.apache.fop.pdf;

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

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

@@ -391,6 +391,9 @@ public class PDFLinkTestCase {
{"examples.html?foo#bar", quote("/URI (examples.html?foo#bar)")},
{"examples.html", quote("<< /URI (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

@@ -0,0 +1,42 @@
/*
* 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

@@ -0,0 +1,42 @@
/*
* 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