FOP-3215: Allow object-streams with signing and encryption
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFDocument.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFDocument.java
index acc4103..8f4ce73 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFDocument.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFDocument.java
@@ -1202,9 +1202,6 @@
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());
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFEncryptionJCE.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFEncryptionJCE.java
index ff2aac6..edebbb2 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFEncryptionJCE.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFEncryptionJCE.java
@@ -837,4 +837,7 @@
return pdfVersion;
}
+ public boolean supportsObjectStream() {
+ return false;
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java
index 7b60384..45b0ee1 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFRoot.java
@@ -348,4 +348,8 @@
af.add(fileSpec);
fileSpec.put("AFRelationship", new PDFName("Data"));
}
+
+ public boolean supportsObjectStream() {
+ return !getDocument().isEncryptionActive();
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFSignature.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFSignature.java
index 1ff7855..f5384be 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFSignature.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFSignature.java
@@ -120,7 +120,11 @@
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;
}
}
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFObjectStreamTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFObjectStreamTestCase.java
index 702c320..537d021 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFObjectStreamTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFObjectStreamTestCase.java
@@ -35,8 +35,22 @@
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 @@
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();
}
}
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFSigningTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFSigningTestCase.java
index fbd11cf..3e46aa3 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFSigningTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFSigningTestCase.java
@@ -41,9 +41,28 @@
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 @@
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"