]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-3215: Allow object-streams with signing and encryption
authorSimon Steiner <ssteiner@apache.org>
Tue, 29 Oct 2024 15:39:22 +0000 (15:39 +0000)
committerSimon Steiner <ssteiner@apache.org>
Tue, 29 Oct 2024 15:39:22 +0000 (15:39 +0000)
fop-core/src/main/java/org/apache/fop/pdf/PDFDocument.java
fop-core/src/main/java/org/apache/fop/pdf/PDFEncryptionJCE.java
fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java
fop-core/src/main/java/org/apache/fop/pdf/PDFSignature.java
fop-core/src/test/java/org/apache/fop/pdf/PDFObjectStreamTestCase.java
fop-core/src/test/java/org/apache/fop/pdf/PDFSigningTestCase.java

index acc41032fab7073fd605822c2495c76f0a754b7c..8f4ce734777d1766611c3169f0f2be047102b318 100644 (file)
@@ -1202,9 +1202,6 @@ public class PDFDocument {
         if (objectStreamsEnabled && linearizationEnabled) {
             throw new UnsupportedOperationException("Linearization and use-object-streams can't be both enabled");
         }
-        if (objectStreamsEnabled && isEncryptionActive()) {
-            throw new UnsupportedOperationException("Encryption and use-object-streams can't be both enabled");
-        }
         return objectStreamsEnabled || (accessibilityEnabled
                 && versionController.getPDFVersion().compareTo(Version.V1_5) >= 0 && !isLinearizationEnabled());
     }
index ff2aac68f44ed9b0363f32a67d4a8beed3ebc754..edebbb23a5c1b62a6538b72af48f54453d4a9146 100644 (file)
@@ -837,4 +837,7 @@ public final class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
         return pdfVersion;
     }
 
+    public boolean supportsObjectStream() {
+        return false;
+    }
 }
index 7b6038467948cdd0f44fdc9f5838c555a414b393..45b0ee1820aaba40f0923e754961935ccaf52b81 100644 (file)
@@ -348,4 +348,8 @@ public class PDFRoot extends PDFDictionary {
         af.add(fileSpec);
         fileSpec.put("AFRelationship", new PDFName("Data"));
     }
+
+    public boolean supportsObjectStream() {
+        return !getDocument().isEncryptionActive();
+    }
 }
index 1ff785553f0f041683a25479b1f3ff27169870f1..f5384be5358b58d1cdb3a87dd347927521dc2ae0 100644 (file)
@@ -120,7 +120,11 @@ public class PDFSignature {
                 startOfDocMDP = countingOutputStream.getByteCount();
                 return super.output(stream);
             }
-            throw new IOException("Disable pdf linearization and use-object-streams");
+            throw new IOException("Disable pdf linearization");
+        }
+
+        public boolean supportsObjectStream() {
+            return false;
         }
     }
 
index 702c320a84c5570e0c4b521ac52474263ade9248..537d0216e87d4c9c0e678291b325ed1dfd978bdf 100644 (file)
@@ -35,8 +35,22 @@ import org.apache.fop.render.pdf.PDFContentGenerator;
 public class PDFObjectStreamTestCase {
     @Test
     public void testObjectStreamsEnabled() throws IOException {
-        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
         PDFDocument doc = new PDFDocument("");
+        String out = buildObjectStreamsPDF(doc);
+        Assert.assertTrue(out.contains("<<\n  /Type /ObjStm\n  /N 3\n  /First 15\n  /Length 260\n>>\n"
+                + "stream\n8 0\n9 52\n4 121\n<<\n/Producer"));
+    }
+
+    @Test
+    public void testObjectStreamsWithEncryption() throws IOException {
+        PDFDocument doc = new PDFDocument("");
+        doc.setEncryption(new PDFEncryptionParams());
+        String out = buildObjectStreamsPDF(doc);
+        Assert.assertTrue(out.contains("<<\n  /Type /ObjStm\n  /N 3\n  /First 16\n  /Length 282\n>>\nstream"));
+    }
+
+    private String buildObjectStreamsPDF(PDFDocument doc) throws IOException {
+        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
         Map<String, List<String>> filterMap = new HashMap<>();
         List<String> filterList = new ArrayList<>();
         filterList.add("null");
@@ -55,7 +69,6 @@ public class PDFObjectStreamTestCase {
         gen.flushPDFDoc();
         doc.outputTrailer(out);
         Assert.assertTrue(out.toString().contains("/Subtype /Image"));
-        Assert.assertTrue(out.toString().contains("<<\n  /Type /ObjStm\n  /N 3\n  /First 15\n  /Length 260\n>>\n"
-                + "stream\n8 0\n9 52\n4 121\n<<\n/Producer"));
+        return out.toString();
     }
 }
index fbd11cf79b0db52e469176f0cf44857cadcd021b..3e46aa34dea7c7501aa1d1ce6ae13b255ec5b108 100644 (file)
@@ -41,9 +41,28 @@ import org.apache.fop.fo.pagination.LayoutMasterSetTestCase;
 
 public class PDFSigningTestCase {
     @Test
-    public void textFO() throws Exception {
+    public void testFO() throws Exception {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        foToOutput(out, MimeConstants.MIME_PDF);
+        foToOutput(out, false);
+        String endStr = checkOutput(out);
+        Assert.assertTrue(endStr.contains("/FT /Sig\n"
+                + "  /Type /Annot\n"
+                + "  /Subtype /Widget\n"
+                + "  /F 132\n"
+                + "  /T (Signature1)\n"
+                + "  /TU (Signature1)\n"
+                + "  /Rect [0 0 0 0]"));
+    }
+
+    @Test
+    public void testWithObjectStreams() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        foToOutput(out, true);
+        String endStr = checkOutput(out);
+        Assert.assertFalse(endStr.contains("/Subtype /Widget"));
+    }
+
+    private String checkOutput(ByteArrayOutputStream out) throws Exception {
         StringTokenizer byteRange = new StringTokenizer(out.toString().split("/ByteRange ")[1]);
         byteRange.nextToken();
         int startOfContents = Integer.parseInt(byteRange.nextToken());
@@ -62,31 +81,28 @@ public class PDFSigningTestCase {
         String endStr = new String(end);
         Assert.assertTrue(endStr.contains(
                 "/ByteRange [0 " + startOfContents + " " + endOfContents + " " + sizeOfEnd + "]"));
-        Assert.assertTrue(endStr.contains("/FT /Sig\n"
-                + "  /Type /Annot\n"
-                + "  /Subtype /Widget\n"
-                + "  /F 132\n"
-                + "  /T (Signature1)\n"
-                + "  /TU (Signature1)\n"
-                + "  /Rect [0 0 0 0]"));
+        return endStr;
     }
 
-    private void foToOutput(ByteArrayOutputStream out, String mimeFopIf) throws Exception {
-        FopFactory fopFactory = getFopFactory();
+    private void foToOutput(ByteArrayOutputStream out, boolean objectStreams) throws Exception {
+        FopFactory fopFactory = getFopFactory(objectStreams);
         FOUserAgent userAgent = fopFactory.newFOUserAgent();
-        Fop fop = fopFactory.newFop(mimeFopIf, userAgent, out);
+        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
         Transformer transformer = TransformerFactory.newInstance().newTransformer();
         Source src = new StreamSource(LayoutMasterSetTestCase.class.getResourceAsStream("side-regions.fo"));
         Result res = new SAXResult(fop.getDefaultHandler());
         transformer.transform(src, res);
     }
 
-    private FopFactory getFopFactory() throws Exception {
+    private FopFactory getFopFactory(boolean objectStreams) throws Exception {
         String pkcs = PDFSigningTestCase.class.getResource("keystore.pkcs12").toString();
         String fopxconf = "<fop version=\"1.0\">\n"
                 + "  <renderers>\n"
-                + "    <renderer mime=\"application/pdf\">\n"
-                + "    <sign-params>\n"
+                + "    <renderer mime=\"application/pdf\">\n";
+        if (objectStreams) {
+            fopxconf += "<use-object-streams>true</use-object-streams>";
+        }
+        fopxconf += "    <sign-params>\n"
                 + "      <keystore>" + pkcs + "</keystore>\n"
                 + "    </sign-params>\n"
                 + "    </renderer>\n"