]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2875: add support for non-ascii characters in pdf file attachment names, fix...
authorMatthias Reischenbacher <matthias@apache.org>
Sat, 27 Jul 2019 13:23:59 +0000 (13:23 +0000)
committerMatthias Reischenbacher <matthias@apache.org>
Sat, 27 Jul 2019 13:23:59 +0000 (13:23 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1863870 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
fop-core/src/main/java/org/apache/fop/pdf/PDFAction.java
fop-core/src/main/java/org/apache/fop/pdf/PDFFactory.java
fop-core/src/main/java/org/apache/fop/pdf/PDFFileSpec.java
fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java
fop-core/src/main/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
fop-core/src/main/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachment.java
fop-core/src/test/java/org/apache/fop/pdf/PDFAttachmentTestCase.java
fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
fop-core/src/test/java/org/apache/fop/pdf/PDFFileSpecTestCase.java [new file with mode: 0644]
fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
fop-core/src/test/java/org/apache/fop/pdf/PDFLinkTestCase.java
fop-core/src/test/java/org/apache/fop/pdf/PDFRootTestCase.java [new file with mode: 0644]
fop-core/src/test/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachmentTest.java [new file with mode: 0644]

index cfc95b3c8a80e356b230e458db8e9ed34db91fae..9d41628c449a794dc7c20d73323547dbb7f0bea7 100644 (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);
         }
     }
 
index 81fd0c38a1be4ab738eae51702256e37c6307bd1..aad24cae91dfbb4907efcf405bf4bf6a05681a4e 100644 (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());
index f9f990c95b79c773595bdf2daf463ad10516679b..b5531d03596b4be501d604eac17ae6e66c5c138c 100644 (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
index 23eb0a63a9cc9cbab283edfc60c0bf1c4599bf63..b230ad879647dc14f65c11026ae100e232b1a79d 100644 (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"));
     }
 }
index 4ad9ee33378daf3ba39497be93c73a672222e615..5ba2cae1bc5e51ea25b20033020c4b632f08da85 100644 (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));
     }
 
index 96e429d6940f1552e5d42f847c7a6b25d39fabb9..dd18308e704c5fa4ac8ae9034185438b6d514501 100644 (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;
     }
 
     /**
index f1e7423a04b73d8253f029752d2e1a3f37aca24e..2d7e659e3e5ada6481bdd64ce2df166629bd6320 100644 (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>>"));
     }
 }
index 61cec5d4aca9ca0ee8d28f5be8e84d966691ebc6..da7a8a0de9d780c3c82641c7017a3658cec1dbbd 100644 (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());
+    }
 }
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFFileSpecTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFFileSpecTestCase.java
new file mode 100644 (file)
index 0000000..b21b5c0
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id: PDFFactoryTestCase.java 1823552 2018-02-08 12:26:33Z ssteiner $ */\r
+\r
+package org.apache.fop.pdf;\r
+\r
+import org.junit.Test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+public class PDFFileSpecTestCase {\r
+\r
+    @Test\r
+    public void testPDFFileSpec() {\r
+        String germanAe = "\u00E4";\r
+        String filename = "test";\r
+        String unicodeFilename = "t" + germanAe + "st";\r
+        PDFFileSpec fileSpec = new PDFFileSpec(filename, unicodeFilename);\r
+        assertEquals(fileSpec.getUnicodeFilename(), unicodeFilename);\r
+        assertEquals(fileSpec.getFilename(), filename);\r
+    }\r
+}\r
index 2f5abd4d95c420752e840961ece22bff69b64c92..06b859d12c9e9e8870c3a4e823a39690e2ab79b4 100644 (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 {
 }
index 34c81967fe1577d148b3288fb77f8c4082634eb5..b4c6a52391c701f6d5bd01fdf5800ed3162ef62e 100644 (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)")}
         });
     }
 
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFRootTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFRootTestCase.java
new file mode 100644 (file)
index 0000000..67703c1
--- /dev/null
@@ -0,0 +1,42 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id: PDFFactoryTestCase.java 1823552 2018-02-08 12:26:33Z ssteiner $ */\r
+\r
+package org.apache.fop.pdf;\r
+\r
+import org.junit.Test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+public class PDFRootTestCase {\r
+\r
+    @Test\r
+    public void testAddAf() {\r
+        String germanAe = "\u00E4";\r
+        String unicodeFilename = "t" + germanAe + "st.pdf";\r
+        PDFFileSpec fileSpec = new PDFFileSpec(unicodeFilename);\r
+\r
+        String filename = fileSpec.getFilename();\r
+\r
+        PDFDocument doc = new PDFDocument("");\r
+        doc.getRoot().addAF(fileSpec);\r
+\r
+        assertEquals(filename, fileSpec.getFilename());\r
+        assertEquals(unicodeFilename, fileSpec.getUnicodeFilename());\r
+    }\r
+}\r
diff --git a/fop-core/src/test/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachmentTest.java b/fop-core/src/test/java/org/apache/fop/render/pdf/extensions/PDFEmbeddedFileAttachmentTest.java
new file mode 100644 (file)
index 0000000..6f6c902
--- /dev/null
@@ -0,0 +1,42 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id: PDFRenderingUtil.java 1761019 2016-09-16 10:43:45Z ssteiner $ */\r
+\r
+package org.apache.fop.render.pdf.extensions;\r
+\r
+import org.junit.Test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertFalse;\r
+\r
+public class PDFEmbeddedFileAttachmentTest {\r
+\r
+    @Test\r
+    public void testGetFilename() {\r
+        String germanAe = "\u00E4";\r
+        String unicodeFilename = "t" + germanAe + "st";\r
+        String src = "src";\r
+        String desc = "desc";\r
+        PDFEmbeddedFileAttachment fileAtt = new PDFEmbeddedFileAttachment(unicodeFilename, src, desc);\r
+        assertEquals(fileAtt.getUnicodeFilename(), unicodeFilename);\r
+        assertFalse(fileAtt.getFilename().contains(germanAe));\r
+        assertEquals(fileAtt.getSrc(), src);\r
+        assertEquals(fileAtt.getDesc(), desc);\r
+    }\r
+\r
+}\r