diff --git a/barcodes/pom.xml b/barcodes/pom.xml
index 30b7a8af74..78706b84b4 100644
--- a/barcodes/pom.xml
+++ b/barcodes/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16barcodesiText 7 - barcodes
diff --git a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeDataMatrixTest.java b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeDataMatrixTest.java
index af955e167b..70857b1b30 100644
--- a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeDataMatrixTest.java
+++ b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeDataMatrixTest.java
@@ -52,13 +52,12 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class BarcodeDataMatrixTest extends ExtendedITextTest {
@@ -66,9 +65,6 @@ public class BarcodeDataMatrixTest extends ExtendedITextTest {
public static final String destinationFolder = "./target/test/com/itextpdf/barcodes/BarcodeDataMatrix/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/barcodes/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -191,6 +187,7 @@ public void barcode07Test() {
String aCode = "aBCdeFG12";
int result = bc.setCode(aCode);
+
Assert.assertEquals(result, BarcodeDataMatrix.DM_ERROR_TEXT_TOO_BIG);
}
@@ -200,6 +197,7 @@ public void barcode08Test() {
barcodeDataMatrix.setWidth(18);
barcodeDataMatrix.setHeight(18);
int result = barcodeDataMatrix.setCode("AbcdFFghijklmnopqrstuWXSQ");
+
Assert.assertEquals(BarcodeDataMatrix.DM_ERROR_TEXT_TOO_BIG, result);
}
@@ -209,6 +207,7 @@ public void barcode09Test() {
barcodeDataMatrix.setWidth(17);
barcodeDataMatrix.setHeight(17);
int result = barcodeDataMatrix.setCode("AbcdFFghijklmnopqrstuWXSQ");
+
Assert.assertEquals(BarcodeDataMatrix.DM_ERROR_INVALID_SQUARE, result);
}
@@ -218,6 +217,7 @@ public void barcode10Test() {
barcodeDataMatrix.setWidth(26);
barcodeDataMatrix.setHeight(12);
int result = barcodeDataMatrix.setCode("AbcdFFghijklmnopqrstuWXSQ");
+
Assert.assertEquals(BarcodeDataMatrix.DM_ERROR_TEXT_TOO_BIG, result);
}
@@ -228,37 +228,38 @@ public void barcode11Test() {
barcodeDataMatrix.setHeight(18);
byte[] str = "AbcdFFghijklmnop".getBytes();
int result = barcodeDataMatrix.setCode(str, 0, str.length);
+
Assert.assertEquals(BarcodeDataMatrix.DM_NO_ERROR, result);
}
@Test
public void barcode12Test() {
- junitExpectedException.expect(IndexOutOfBoundsException.class);
BarcodeDataMatrix barcodeDataMatrix = new BarcodeDataMatrix();
barcodeDataMatrix.setWidth(18);
barcodeDataMatrix.setHeight(18);
byte[] str = "AbcdFFghijklmnop".getBytes();
- barcodeDataMatrix.setCode(str, -1, str.length);
+
+ Exception e = Assert.assertThrows(IndexOutOfBoundsException.class, () -> barcodeDataMatrix.setCode(str, -1, str.length));
}
@Test
public void barcode13Test() {
- junitExpectedException.expect(IndexOutOfBoundsException.class);
BarcodeDataMatrix barcodeDataMatrix = new BarcodeDataMatrix();
barcodeDataMatrix.setWidth(18);
barcodeDataMatrix.setHeight(18);
byte[] str = "AbcdFFghijklmnop".getBytes();
- barcodeDataMatrix.setCode(str, 0, str.length + 1);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> barcodeDataMatrix.setCode(str, 0, str.length + 1));
}
@Test
public void barcode14Test() {
- junitExpectedException.expect(IndexOutOfBoundsException.class);
BarcodeDataMatrix barcodeDataMatrix = new BarcodeDataMatrix();
barcodeDataMatrix.setWidth(18);
barcodeDataMatrix.setHeight(18);
byte[] str = "AbcdFFghijklmnop".getBytes();
- barcodeDataMatrix.setCode(str, 0, -1);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> barcodeDataMatrix.setCode(str, 0, -1));
}
@Test
@@ -268,6 +269,7 @@ public void barcode15Test() {
barcodeDataMatrix.setHeight(18);
byte[] str = "AbcdFFghijklmnop".getBytes();
int result = barcodeDataMatrix.setCode(str, str.length, 0);
+
Assert.assertEquals(BarcodeDataMatrix.DM_NO_ERROR, result);
}
diff --git a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeEANUnitTest.java b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeEANUnitTest.java
index 922d4fe685..1dae99b9fa 100644
--- a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeEANUnitTest.java
+++ b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodeEANUnitTest.java
@@ -51,19 +51,14 @@ This file is part of the iText (R) project.
import java.io.ByteArrayOutputStream;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class BarcodeEANUnitTest extends ExtendedITextTest {
public static final float EPS = 0.0001f;
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void calculateEANParityTest() throws PdfException {
int expectedParity = BarcodeEAN.calculateEANParity("1234567890");
@@ -227,9 +222,6 @@ public void getBarcodeSizeSUPP2Test() throws PdfException {
@Test
public void getBarcodeSizeIncorrectTypeTest() throws PdfException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage("Invalid code type");
-
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
Barcode1D barcode = new BarcodeEAN(document);
@@ -239,6 +231,7 @@ public void getBarcodeSizeIncorrectTypeTest() throws PdfException {
barcode.setCodeType(1234);
// We do expect an exception here
- barcode.getBarcodeSize();
+ Exception e = Assert.assertThrows(PdfException.class, () -> barcode.getBarcodeSize());
+ Assert.assertEquals("Invalid code type", e.getMessage());
}
}
diff --git a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java
index 54fe72e238..4a8d75ae1c 100644
--- a/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java
+++ b/barcodes/src/test/java/com/itextpdf/barcodes/BarcodePDF417Test.java
@@ -62,10 +62,8 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class BarcodePDF417Test extends ExtendedITextTest {
@@ -77,9 +75,6 @@ public static void beforeClass() {
createDestinationFolder(destinationFolder);
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void barcode01Test() throws IOException, PdfException, InterruptedException {
String filename = "barcode417_01.pdf";
@@ -440,9 +435,6 @@ public void barcode417OptionsWithBarcodeGenerationTest() {
@Test
public void barcode417OptionsWithBarcodeGenerationInvalidSizeTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage("Invalid codeword size.");
-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = new PdfWriter(baos);
PdfDocument document = new PdfDocument(writer);
@@ -452,8 +444,11 @@ public void barcode417OptionsWithBarcodeGenerationInvalidSizeTest() {
BarcodePDF417 barcode = new BarcodePDF417();
barcode.setOptions(64);
- barcode.placeBarcode(canvas, null);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> barcode.placeBarcode(canvas, null)
+ );
+ Assert.assertEquals("Invalid codeword size.", e.getMessage());
Assert.assertEquals(64, barcode.getOptions());
}
diff --git a/font-asian/pom.xml b/font-asian/pom.xml
index c2fc5fd7ee..5a43dc0d66 100644
--- a/font-asian/pom.xml
+++ b/font-asian/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16font-asianiText 7 - Asian fonts
diff --git a/forms/pom.xml b/forms/pom.xml
index fb42fb40af..cc11f50353 100644
--- a/forms/pom.xml
+++ b/forms/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16formsiText 7 - forms
diff --git a/forms/src/main/java/com/itextpdf/forms/xfa/XfaForm.java b/forms/src/main/java/com/itextpdf/forms/xfa/XfaForm.java
index 36ebb40c0a..c3942b0b07 100644
--- a/forms/src/main/java/com/itextpdf/forms/xfa/XfaForm.java
+++ b/forms/src/main/java/com/itextpdf/forms/xfa/XfaForm.java
@@ -54,28 +54,24 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfVersion;
import com.itextpdf.kernel.pdf.VersionConforming;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
import com.itextpdf.kernel.xmp.XmlDomWriter;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
-
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -107,13 +103,14 @@ public XfaForm() {
/**
* Creates an XFA form by the stream containing all xml information
+ *
* @param inputStream the InputStream
*/
public XfaForm(InputStream inputStream) {
try {
initXfaForm(inputStream);
} catch (Exception e) {
- throw new PdfException(e);
+ throw new PdfException(e.getMessage(), e);
}
}
@@ -140,7 +137,7 @@ public XfaForm(PdfDictionary acroFormDictionary) {
try {
initXfaForm(xfa);
} catch (Exception e) {
- throw new PdfException(e);
+ throw new PdfException(e.getMessage(), e);
}
}
}
@@ -157,7 +154,7 @@ public XfaForm(PdfDocument pdfDocument) {
try {
initXfaForm(xfa);
} catch (Exception e) {
- throw new PdfException(e);
+ throw new PdfException(e.getMessage(), e);
}
}
}
@@ -497,17 +494,12 @@ public void fillXfaForm(InputSource is) throws IOException {
* @throws java.io.IOException if any I/O issue occurs on the {@link InputSource}
*/
public void fillXfaForm(InputSource is, boolean readOnly) throws IOException {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- DocumentBuilder db;
try {
- db = dbf.newDocumentBuilder();
- db.setEntityResolver(new SafeEmptyEntityResolver());
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
Document newdoc = db.parse(is);
fillXfaForm(newdoc.getDocumentElement(), readOnly);
- } catch (ParserConfigurationException e) {
- throw new PdfException(e);
} catch (SAXException e) {
- throw new PdfException(e);
+ throw new PdfException(e.getMessage(), e);
}
}
@@ -631,11 +623,8 @@ private void initXfaForm(PdfObject xfa) throws IOException, ParserConfigurationE
initXfaForm(new ByteArrayInputStream(bout.toByteArray()));
}
- private void initXfaForm(InputStream inputStream) throws ParserConfigurationException, IOException, SAXException {
- DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
- fact.setNamespaceAware(true);
- DocumentBuilder db = fact.newDocumentBuilder();
- db.setEntityResolver(new SafeEmptyEntityResolver());
+ private void initXfaForm(InputStream inputStream) throws IOException, SAXException {
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(true, false);
setDomDocument(db.parse(inputStream));
xfaPresent = true;
}
@@ -696,12 +685,4 @@ private Node findDataNode(Node datasetsNode) {
}
return null;
}
-
- // Prevents XXE attacks
- private static class SafeEmptyEntityResolver implements EntityResolver {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- }
-
}
diff --git a/forms/src/main/java/com/itextpdf/forms/xfdf/XfdfFileUtils.java b/forms/src/main/java/com/itextpdf/forms/xfdf/XfdfFileUtils.java
index 1a7c857a56..7df65453da 100644
--- a/forms/src/main/java/com/itextpdf/forms/xfdf/XfdfFileUtils.java
+++ b/forms/src/main/java/com/itextpdf/forms/xfdf/XfdfFileUtils.java
@@ -42,24 +42,20 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.forms.xfdf;
-import org.w3c.dom.Document;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
+import java.io.InputStream;
+import java.io.OutputStream;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.StringReader;
+import org.w3c.dom.Document;
final class XfdfFileUtils {
@@ -68,32 +64,40 @@ private XfdfFileUtils() {
/**
* Creates a new xml-styled document for writing xfdf info.
+ *
* @throws ParserConfigurationException in case of failure to create a new document.
*/
- static Document createNewXfdfDocument() throws ParserConfigurationException {
- DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
- documentBuilder.setEntityResolver(new XfdfFileUtils.SafeEmptyEntityResolver());
- return documentBuilder.newDocument();
+ static Document createNewXfdfDocument() {
+ try {
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
+ return db.newDocument();
+ } catch (Exception e) {
+ throw new PdfException(e.getMessage(), e);
+ }
}
/**
* Creates a new xfdf document based on given input stream.
+ *
* @param inputStream containing xfdf info.
*/
- static Document createXfdfDocumentFromStream(InputStream inputStream) throws ParserConfigurationException, IOException, SAXException {
- DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
- documentBuilder.setEntityResolver(new XfdfFileUtils.SafeEmptyEntityResolver());
- return documentBuilder.parse(inputStream);
+ static Document createXfdfDocumentFromStream(InputStream inputStream) {
+ try {
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
+ return db.parse(inputStream);
+ } catch (Exception e) {
+ throw new PdfException(e.getMessage(), e);
+ }
}
/**
- * Saves the info from output stream to xml-styled document.
- * @param document to save info to.
- * @param outputStream the stream containing xfdf info.
+ * Saves the info from XML-styled {@link Document} to {@link OutputStream}.
+ *
+ * @param document input {@link Document} that contains XFDF info
+ * @param outputStream the output stream
*/
- static void saveXfdfDocumentToFile(Document document, OutputStream outputStream) throws TransformerException {
+ static void saveXfdfDocumentToFile(Document document, OutputStream outputStream)
+ throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
@@ -103,11 +107,4 @@ static void saveXfdfDocumentToFile(Document document, OutputStream outputStream)
StreamResult streamResult = new StreamResult(outputStream);
transformer.transform(domSource, streamResult);
}
-
- // Prevents XXE attacks
- private static class SafeEmptyEntityResolver implements EntityResolver {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- }
}
diff --git a/forms/src/test/java/com/itextpdf/forms/XfdfUnitTest.java b/forms/src/test/java/com/itextpdf/forms/XfdfUnitTest.java
index c5e5da7c82..9b1d9efa60 100644
--- a/forms/src/test/java/com/itextpdf/forms/XfdfUnitTest.java
+++ b/forms/src/test/java/com/itextpdf/forms/XfdfUnitTest.java
@@ -28,25 +28,17 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class XfdfUnitTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void fitObjectWithEmptyPageTest(){
- junitExpectedException.expect(XfdfException.class);
- junitExpectedException.expectMessage(XfdfException.PAGE_IS_MISSING);
-
- FitObject fitObject = new FitObject(null);
-
- Assert.fail();
+ Exception e = Assert.assertThrows(XfdfException.class,
+ () -> new FitObject(null)
+ );
+ Assert.assertEquals(XfdfException.PAGE_IS_MISSING, e.getMessage());
}
-
}
diff --git a/forms/src/test/java/com/itextpdf/forms/XfdfWriterTest.java b/forms/src/test/java/com/itextpdf/forms/XfdfWriterTest.java
index bae0e48cc0..aa0f6486e9 100644
--- a/forms/src/test/java/com/itextpdf/forms/XfdfWriterTest.java
+++ b/forms/src/test/java/com/itextpdf/forms/XfdfWriterTest.java
@@ -58,12 +58,9 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import org.xml.sax.SAXException;
-
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.FileInputStream;
@@ -75,10 +72,6 @@ public class XfdfWriterTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/forms/XfdfWriterTest/";
public static final String destinationFolder = "./target/test/com/itextpdf/forms/XfdfWriterTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
-
@BeforeClass
public static void beforeClass() {
createDestinationFolder(destinationFolder);
@@ -1047,10 +1040,6 @@ public void xfdfDropDown() throws IOException, ParserConfigurationException, SAX
@Test
public void xfdfEmptyAttributeTest() {
-
- junitExpectedException.expect(XfdfException.class);
- junitExpectedException.expectMessage(XfdfException.ATTRIBUTE_NAME_OR_VALUE_MISSING);
-
XfdfObject xfdfObject = new XfdfObject();
AnnotsObject annots = new AnnotsObject();
@@ -1064,8 +1053,13 @@ public void xfdfEmptyAttributeTest() {
String valuePresent = "value";
String valueAbsent = null;
- annot.addAttribute(new AttributeObject(nameAbsent, valuePresent));
- annot.addAttribute(new AttributeObject(namePresent, valueAbsent));
-
+ Exception e = Assert.assertThrows(XfdfException.class,
+ () -> annot.addAttribute(new AttributeObject(nameAbsent, valuePresent))
+ );
+ Assert.assertEquals(XfdfException.ATTRIBUTE_NAME_OR_VALUE_MISSING, e.getMessage());
+ Exception e2 = Assert.assertThrows(XfdfException.class,
+ () -> annot.addAttribute(new AttributeObject(namePresent, valueAbsent))
+ );
+ Assert.assertEquals(XfdfException.ATTRIBUTE_NAME_OR_VALUE_MISSING, e2.getMessage());
}
}
diff --git a/forms/src/test/java/com/itextpdf/forms/xfa/SecurityTestXmlParserFactory.java b/forms/src/test/java/com/itextpdf/forms/xfa/SecurityTestXmlParserFactory.java
new file mode 100644
index 0000000000..b5fb6c83b9
--- /dev/null
+++ b/forms/src/test/java/com/itextpdf/forms/xfa/SecurityTestXmlParserFactory.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.forms.xfa;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.test.ExceptionTestUtil;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+public class SecurityTestXmlParserFactory extends DefaultSafeXmlParserFactory {
+
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ DocumentBuilder db;
+ try {
+ db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+
+ db.setEntityResolver(new TestEntityResolver());
+ return db;
+ }
+
+ private static class TestEntityResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) {
+ throw new PdfException(ExceptionTestUtil.getXxeTestMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/forms/src/test/java/com/itextpdf/forms/xfa/XfaSecurityTest.java b/forms/src/test/java/com/itextpdf/forms/xfa/XfaSecurityTest.java
new file mode 100644
index 0000000000..efc57160a5
--- /dev/null
+++ b/forms/src/test/java/com/itextpdf/forms/xfa/XfaSecurityTest.java
@@ -0,0 +1,148 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.forms.xfa;
+
+import com.itextpdf.forms.PdfAcroForm;
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfReader;
+import com.itextpdf.kernel.pdf.PdfWriter;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
+import com.itextpdf.test.ExceptionTestUtil;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.IntegrationTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(IntegrationTest.class)
+public class XfaSecurityTest extends ExtendedITextTest {
+
+ private static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/";
+
+ private static final String DTD_EXCEPTION_MESSAGE = ExceptionTestUtil.getDoctypeIsDisallowedExceptionMessage();
+
+ private static final String XFA_WITH_DTD_XML = "\n"
+ + "\n"
+ + "\n"
+ + "\n"
+ + "\n";
+
+ @Before
+ public void resetXmlParserFactoryToDefault() {
+ XmlProcessorCreator.setXmlParserFactory(new DefaultSafeXmlParserFactory());
+ }
+
+ @Test
+ public void xfaExternalFileTest() throws IOException {
+ xfaSecurityExceptionTest(SOURCE_FOLDER + "xfaExternalFile.pdf");
+ }
+
+ @Test
+ public void xfaExternalConnectionTest() throws IOException {
+ xfaSecurityExceptionTest(SOURCE_FOLDER + "xfaExternalConnection.pdf");
+ }
+
+ @Test
+ public void xfaInternalEntityTest() throws IOException {
+ xfaSecurityExceptionTest(SOURCE_FOLDER + "xfaInternalEntity.pdf");
+ }
+
+ @Test
+ public void xfaExternalFileCustomFactoryTest() throws IOException {
+ String inFileName = SOURCE_FOLDER + "xfaExternalFile.pdf";
+ XmlProcessorCreator.setXmlParserFactory(new SecurityTestXmlParserFactory());
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inFileName),
+ new PdfWriter(new ByteArrayOutputStream()))) {
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfAcroForm.getAcroForm(pdfDoc, true)
+ );
+ Assert.assertEquals(ExceptionTestUtil.getXxeTestMessage(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void xfaExternalFileXfaFormTest() throws IOException {
+ String inFileName = SOURCE_FOLDER + "xfaExternalFile.pdf";
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inFileName))) {
+ Exception e = Assert.assertThrows(PdfException.class, () -> new XfaForm(pdfDoc));
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+
+ @Test
+ public void xfaWithDtdXfaFormTest() throws IOException {
+ try (InputStream inputStream = new ByteArrayInputStream(XFA_WITH_DTD_XML.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(PdfException.class, () -> new XfaForm(inputStream));
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+
+ @Test
+ public void fillXfaFormTest() throws IOException {
+ try (InputStream inputStream = new ByteArrayInputStream(XFA_WITH_DTD_XML.getBytes(StandardCharsets.UTF_8))) {
+ XfaForm form = new XfaForm();
+ Exception e = Assert.assertThrows(PdfException.class, () -> form.fillXfaForm(inputStream, true));
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+
+ private void xfaSecurityExceptionTest(String inputFileName) throws IOException {
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputFileName),
+ new PdfWriter(new ByteArrayOutputStream()))) {
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfAcroForm.getAcroForm(pdfDoc, true)
+ );
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+}
diff --git a/forms/src/test/java/com/itextpdf/forms/xfdf/ExceptionTestXmlParserFactory.java b/forms/src/test/java/com/itextpdf/forms/xfdf/ExceptionTestXmlParserFactory.java
new file mode 100644
index 0000000000..47cd505acd
--- /dev/null
+++ b/forms/src/test/java/com/itextpdf/forms/xfdf/ExceptionTestXmlParserFactory.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.forms.xfdf;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.test.ExceptionTestUtil;
+
+import javax.xml.parsers.DocumentBuilder;
+
+public class ExceptionTestXmlParserFactory extends DefaultSafeXmlParserFactory {
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ throw new PdfException(ExceptionTestUtil.getXxeTestMessage());
+ }
+}
diff --git a/forms/src/test/java/com/itextpdf/forms/xfdf/SecurityTestXmlParserFactory.java b/forms/src/test/java/com/itextpdf/forms/xfdf/SecurityTestXmlParserFactory.java
new file mode 100644
index 0000000000..7493f2d71d
--- /dev/null
+++ b/forms/src/test/java/com/itextpdf/forms/xfdf/SecurityTestXmlParserFactory.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.forms.xfdf;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+class SecurityTestXmlParserFactory extends DefaultSafeXmlParserFactory {
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ DocumentBuilder db;
+ try {
+ db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+ db.setEntityResolver(new TestEntityResolver());
+ return db;
+ }
+
+ private static class TestEntityResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) {
+ throw new PdfException("Test message");
+ }
+ }
+}
\ No newline at end of file
diff --git a/forms/src/test/java/com/itextpdf/forms/xfdf/XfdfSecurityTest.java b/forms/src/test/java/com/itextpdf/forms/xfdf/XfdfSecurityTest.java
new file mode 100644
index 0000000000..5ae919cd8b
--- /dev/null
+++ b/forms/src/test/java/com/itextpdf/forms/xfdf/XfdfSecurityTest.java
@@ -0,0 +1,110 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.forms.xfdf;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
+import com.itextpdf.test.ExceptionTestUtil;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.UnitTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(UnitTest.class)
+public class XfdfSecurityTest extends ExtendedITextTest {
+
+ private static final String XFDF_WITH_XXE = " \n"
+ + " ]>\n"
+ + "\n"
+ + "\n"
+ + "ABCDEFGH&xxe;\n"
+ + "\n"
+ + "";
+
+ @Test
+ public void xxeVulnerabilityXfdfTest()
+ throws IOException {
+ XmlProcessorCreator.setXmlParserFactory(new DefaultSafeXmlParserFactory());
+ try (InputStream inputStream = new ByteArrayInputStream(XFDF_WITH_XXE.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> XfdfFileUtils.createXfdfDocumentFromStream(inputStream)
+ );
+ Assert.assertEquals(ExceptionTestUtil.getDoctypeIsDisallowedExceptionMessage(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void xxeVulnerabilityXfdfCustomXmlParserTest()
+ throws IOException {
+ XmlProcessorCreator.setXmlParserFactory(new SecurityTestXmlParserFactory());
+ try (InputStream inputStream = new ByteArrayInputStream(XFDF_WITH_XXE.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> XfdfFileUtils.createXfdfDocumentFromStream(inputStream)
+ );
+ Assert.assertEquals("Test message", e.getMessage());
+ }
+ }
+
+ @Test
+ public void customXmlParserCreateNewXfdfDocumentExceptionTest()
+ throws IOException {
+ XmlProcessorCreator.setXmlParserFactory(new ExceptionTestXmlParserFactory());
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> XfdfFileUtils.createNewXfdfDocument()
+ );
+ Assert.assertEquals(ExceptionTestUtil.getXxeTestMessage(), e.getMessage());
+ }
+}
diff --git a/forms/src/test/resources/com/itextpdf/forms/PdfFormFieldMultilineTextTest/cmp_multilineFormFieldNewLineFontType3Test.pdf b/forms/src/test/resources/com/itextpdf/forms/PdfFormFieldMultilineTextTest/cmp_multilineFormFieldNewLineFontType3Test.pdf
index 30e4628074..42461a60ad 100644
Binary files a/forms/src/test/resources/com/itextpdf/forms/PdfFormFieldMultilineTextTest/cmp_multilineFormFieldNewLineFontType3Test.pdf and b/forms/src/test/resources/com/itextpdf/forms/PdfFormFieldMultilineTextTest/cmp_multilineFormFieldNewLineFontType3Test.pdf differ
diff --git a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalConnection.pdf b/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalConnection.pdf
deleted file mode 100644
index a6ae0b7359..0000000000
Binary files a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalConnection.pdf and /dev/null differ
diff --git a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/xfaExternalConnection.pdf b/forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaExternalConnection.pdf
similarity index 100%
rename from forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/xfaExternalConnection.pdf
rename to forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaExternalConnection.pdf
diff --git a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/xfaExternalFile.pdf b/forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaExternalFile.pdf
similarity index 100%
rename from forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/xfaExternalFile.pdf
rename to forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaExternalFile.pdf
diff --git a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalFile.pdf b/forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaInternalEntity.pdf
similarity index 92%
rename from forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalFile.pdf
rename to forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaInternalEntity.pdf
index 5a77104c62..e28a0a914a 100644
Binary files a/forms/src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/cmp_outXfaExternalFile.pdf and b/forms/src/test/resources/com/itextpdf/forms/xfa/XfaSecurityTest/xfaInternalEntity.pdf differ
diff --git a/hyph/pom.xml b/hyph/pom.xml
index 3d33c1b32c..9d129de9c3 100644
--- a/hyph/pom.xml
+++ b/hyph/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16hyphiText 7 - hyph
diff --git a/hyph/src/main/resources/com/itextpdf/hyph/da.xml b/hyph/src/main/resources/com/itextpdf/hyph/da.xml
index 44174cf558..5caa986a94 100644
--- a/hyph/src/main/resources/com/itextpdf/hyph/da.xml
+++ b/hyph/src/main/resources/com/itextpdf/hyph/da.xml
@@ -15,7 +15,6 @@
limitations under the License.
-->
-
diff --git a/hyph/src/main/resources/com/itextpdf/hyph/it.xml b/hyph/src/main/resources/com/itextpdf/hyph/it.xml
index 948a1c2bb8..fa5cf39618 100644
--- a/hyph/src/main/resources/com/itextpdf/hyph/it.xml
+++ b/hyph/src/main/resources/com/itextpdf/hyph/it.xml
@@ -1,5 +1,4 @@
-
diff --git a/hyph/src/main/resources/com/itextpdf/hyph/nl.xml b/hyph/src/main/resources/com/itextpdf/hyph/nl.xml
index 2877794b2d..008d06e24f 100644
--- a/hyph/src/main/resources/com/itextpdf/hyph/nl.xml
+++ b/hyph/src/main/resources/com/itextpdf/hyph/nl.xml
@@ -1,5 +1,4 @@
-
-
аÐ
diff --git a/hyph/src/main/resources/com/itextpdf/hyph/sk.xml b/hyph/src/main/resources/com/itextpdf/hyph/sk.xml
index e990d1cb9e..a04d48775b 100644
--- a/hyph/src/main/resources/com/itextpdf/hyph/sk.xml
+++ b/hyph/src/main/resources/com/itextpdf/hyph/sk.xml
@@ -1,5 +1,4 @@
-
diff --git a/io/pom.xml b/io/pom.xml
index 76bbf8f43b..d55bb95f87 100644
--- a/io/pom.xml
+++ b/io/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16ioiText 7 - io
diff --git a/io/src/main/java/com/itextpdf/io/LogMessageConstant.java b/io/src/main/java/com/itextpdf/io/LogMessageConstant.java
index f1928dffda..2e1199d16b 100644
--- a/io/src/main/java/com/itextpdf/io/LogMessageConstant.java
+++ b/io/src/main/java/com/itextpdf/io/LogMessageConstant.java
@@ -82,6 +82,11 @@ public final class LogMessageConstant {
public static final String COMB_FLAG_MAY_BE_SET_ONLY_IF_MAXLEN_IS_PRESENT = "The Comb flag may be set only if the MaxLen entry is present in the text field dictionary and if the Multiline, Password, and FileSelect flags are clear.";
public static final String COULD_NOT_FIND_GLYPH_WITH_CODE = "Could not find glyph with the following code: {0}";
public static final String CREATED_ROOT_TAG_HAS_MAPPING = "Created root tag has role mapping: \"/Document\" role{0} is mapped{1}. Resulting tag structure might have invalid root tag.";
+ public static final String CREATE_COPY_SHOULD_BE_OVERRIDDEN = "While processing an instance of TextRenderer, "
+ + "iText uses createCopy() to create glyph lines of specific fonts, which represent its parts. "
+ + "So if one extends TextRenderer, one should override createCopy, otherwise if FontSelector "
+ + "related logic is triggered, copies of this TextRenderer will have the default behavior "
+ + "rather than the custom one.";
public static final String DESTINATION_NOT_PERMITTED_WHEN_ACTION_IS_SET = "Destinations are not permitted for link annotations that already have actions. The old action will be removed.";
public static final String DIRECTONLY_OBJECT_CANNOT_BE_INDIRECT = "DirectOnly object cannot be indirect";
public static final String DOCFONT_HAS_ILLEGAL_DIFFERENCES = "Document Font has illegal differences array. Entry {0} references a glyph ID over 255 and will be ignored.";
@@ -110,6 +115,8 @@ public final class LogMessageConstant {
public static final String FAILED_TO_PROCESS_A_TRANSFORMATION_MATRIX = "Failed to process a transformation matrix which is noninvertible. Some content may be placed not as expected.";
public static final String FIELD_VALUE_IS_NOT_CONTAINED_IN_OPT_ARRAY = "Value \"{0}\" is not contained in /Opt array of field \"{1}\".";
public static final String FILE_CHANNEL_CLOSING_FAILED = "Closing of the file channel this source is based on failed.";
+ public static final String FLEX_ITEM_LAYOUT_RESULT_IS_NOT_FULL =
+ "Flex item layout result isn't full, but it must be. The cross size of the flex item will be 0.";
public static final String FLUSHED_OBJECT_CONTAINS_FREE_REFERENCE = "Flushed object contains indirect reference which is free. Null object will be written instead.";
public static final String FLUSHED_OBJECT_CONTAINS_REFERENCE_WHICH_NOT_REFER_TO_ANY_OBJECT = "Flushed object contains indirect reference which doesn't refer to any other object. Null object will be written instead.";
public static final String FONT_DICTIONARY_WITH_NO_FONT_DESCRIPTOR = "Font dictionary does not contain required /FontDescriptor entry.";
@@ -120,6 +127,10 @@ public final class LogMessageConstant {
public static final String FONT_SUBSET_ISSUE = "Font subset issue. Full font will be embedded.";
public static final String FORBID_RELEASE_IS_SET = "ForbidRelease flag is set and release is called. Releasing will not be performed.";
public static final String FORM_FIELD_WAS_FLUSHED = "A form field was flushed. There's no way to create this field in the AcroForm dictionary.";
+ public static final String GET_NEXT_RENDERER_SHOULD_BE_OVERRIDDEN = "If a renderer overflows, "
+ + "iText uses this method to create another renderer for the overflow part. So if one wants "
+ + "to extend the renderer, one should override this method: otherwise the default method "
+ + "will be used and thus the default rather than the custom renderer will be created.";
public static final String GPOS_LOOKUP_SUBTABLE_FORMAT_NOT_SUPPORTED =
"Subtable format {0} of GPOS Lookup Type {1} is not supported yet";
public static final String GRAPHICS_STATE_WAS_DELETED = "Graphics state is always deleted after event dispatching. If you want to preserve it in renderer info, use preserveGraphicsState method after receiving renderer info.";
@@ -143,6 +154,7 @@ public final class LogMessageConstant {
public static final String INDIRECT_REFERENCE_USED_IN_FLUSHED_OBJECT_MADE_FREE = "An attempt is made to free an indirect reference which was already used in the flushed object. Indirect reference wasn't freed.";
public static final String INLINE_BLOCK_ELEMENT_WILL_BE_CLIPPED = "Inline block element does not fit into parent element and will be clipped";
public static final String INPUT_STREAM_CONTENT_IS_LOST_ON_PDFSTREAM_SERIALIZATION = "PdfStream contains not null input stream. It's content will be lost in serialized object.";
+ public static final String INVALID_DISTRIBUTION_POINT = "Skipped CRL: {0}";
public static final String INVALID_DESTINATION_TYPE = "When destination's not associated with a Remote or Embedded Go-To action, it shall specify page dictionary instead of page number. Otherwise destination might be considered invalid";
public static final String INVALID_INDIRECT_REFERENCE = "Invalid indirect reference {0} {1} R";
public static final String INVALID_KEY_VALUE_KEY_0_HAS_NULL_VALUE = "Invalid key value: key {0} has null value.";
diff --git a/io/src/main/java/com/itextpdf/io/font/FontMetrics.java b/io/src/main/java/com/itextpdf/io/font/FontMetrics.java
index 32cbd3a4cd..926d3e1a5c 100644
--- a/io/src/main/java/com/itextpdf/io/font/FontMetrics.java
+++ b/io/src/main/java/com/itextpdf/io/font/FontMetrics.java
@@ -118,14 +118,39 @@ public int[] getGlyphWidths() {
return glyphWidths;
}
+ /**
+ * Gets typo (a.k.a. sTypo or OS/2) vertical metric corresponding to ascender.
+ *
+ *
+ * Typo vertical metrics are the primary source for iText ascender/descender calculations.
+ *
+ * @return typo ascender value in normalized 1000-units
+ */
public int getTypoAscender() {
return typoAscender;
}
+ /**
+ * Gets typo (a.k.a. sTypo or OS/2) vertical metric corresponding to descender.
+ *
+ *
+ * Typo vertical metrics are the primary source for iText ascender/descender calculations.
+ *
+ * @return typo descender value in normalized 1000-units
+ */
public int getTypoDescender() {
return typoDescender;
}
+ /**
+ * Gets the capital letters height.
+ *
+ *
+ * This property defines the vertical coordinate of the top of flat capital letters,
+ * measured from the baseline.
+ *
+ * @return cap height in 1000-units
+ */
public int getCapHeight() {
return capHeight;
}
@@ -237,14 +262,39 @@ protected void setGlyphWidths(int[] glyphWidths) {
this.glyphWidths = glyphWidths;
}
+ /**
+ * Sets typo (a.k.a. sTypo or OS/2) vertical metric corresponding to ascender.
+ *
+ *
+ * Typo vertical metrics are the primary source for iText ascender/descender calculations.
+ *
+ * @param typoDescender typo descender value in normalized 1000-units
+ */
+ protected void setTypoDescender(int typoDescender) {
+ this.typoDescender = (int) (typoDescender * normalizationCoef);
+ }
+
+ /**
+ * Sets the capital letters height.
+ *
+ *
+ * This property defines the vertical coordinate of the top of flat capital letters,
+ * measured from the baseline.
+ *
+ * @param capHeight cap height in 1000-units
+ */
protected void setCapHeight(int capHeight) {
this.capHeight = (int) (capHeight * normalizationCoef);
}
diff --git a/io/src/main/java/com/itextpdf/io/font/FontProgram.java b/io/src/main/java/com/itextpdf/io/font/FontProgram.java
index 0b0bc5bda2..2aa0afa25d 100644
--- a/io/src/main/java/com/itextpdf/io/font/FontProgram.java
+++ b/io/src/main/java/com/itextpdf/io/font/FontProgram.java
@@ -200,14 +200,29 @@ static String trimFontStyle(String name) {
}
}
+ /**
+ * Sets typo ascender. See also {@link FontMetrics#setTypoAscender(int)}.
+ *
+ * @param ascender typo ascender value in 1000-units
+ */
protected void setTypoAscender(int ascender) {
fontMetrics.setTypoAscender(ascender);
}
+ /**
+ * Sets typo descender. See also {@link FontMetrics#setTypoDescender(int)}.
+ *
+ * @param descender typo descender value in 1000-units
+ */
protected void setTypoDescender(int descender) {
fontMetrics.setTypoDescender(descender);
}
+ /**
+ * Sets the capital letters height. See also {@link FontMetrics#setCapHeight(int)}.
+ *
+ * @param capHeight cap height in 1000-units
+ */
protected void setCapHeight(int capHeight) {
fontMetrics.setCapHeight(capHeight);
}
@@ -217,7 +232,8 @@ protected void setXHeight(int xHeight) {
}
/**
- * Sets the PostScript italic angel.
+ * Sets the PostScript italic angle.
+ *
*
* Italic angle in counter-clockwise degrees from the vertical. Zero for upright text, negative for text that leans to the right (forward).
*
diff --git a/io/src/main/java/com/itextpdf/io/image/ImageTypeDetector.java b/io/src/main/java/com/itextpdf/io/image/ImageTypeDetector.java
index d4ad102369..b9f7305ee8 100644
--- a/io/src/main/java/com/itextpdf/io/image/ImageTypeDetector.java
+++ b/io/src/main/java/com/itextpdf/io/image/ImageTypeDetector.java
@@ -49,7 +49,8 @@ private ImageTypeDetector() {
}
/**
- * Detect image type by magic bytes given the byte array source
+ * Detect image type by magic bytes given the byte array source.
+ *
* @param source image bytes
* @return detected image type, see{@link ImageType}. Returns {@link ImageType#NONE} if image type is unknown
*/
@@ -59,7 +60,8 @@ public static ImageType detectImageType(byte[] source) {
}
/**
- * Detect image type by magic bytes given the source URL
+ * Detect image type by magic bytes given the source URL.
+ *
* @param source image URL
* @return detected image type, see{@link ImageType}. Returns {@link ImageType#NONE} if image type is unknown
*/
@@ -68,6 +70,17 @@ public static ImageType detectImageType(URL source) {
return detectImageTypeByHeader(header);
}
+ /**
+ * Detect image type by magic bytes given the input stream.
+ *
+ * @param stream image stream
+ * @return detected image type, see{@link ImageType}. Returns {@link ImageType#NONE} if image type is unknown
+ */
+ public static ImageType detectImageType(InputStream stream) {
+ byte[] header = readImageType(stream);
+ return detectImageTypeByHeader(header);
+ }
+
private static ImageType detectImageTypeByHeader(byte[] header) {
if (imageTypeIs(header, gif)) {
return ImageType.GIF;
@@ -99,6 +112,14 @@ private static boolean imageTypeIs(byte[] imageType, byte[] compareWith) {
private static byte[] readImageType(URL source) {
try (InputStream stream = UrlUtil.openStream(source)) {
+ return readImageType(stream);
+ } catch (java.io.IOException e) {
+ throw new IOException(IOException.IoException, e);
+ }
+ }
+
+ private static byte[] readImageType(InputStream stream) {
+ try {
byte[] bytes = new byte[8];
stream.read(bytes);
return bytes;
diff --git a/io/src/main/java/com/itextpdf/io/util/GhostscriptHelper.java b/io/src/main/java/com/itextpdf/io/util/GhostscriptHelper.java
index 9ae020245c..7aeaf05c15 100644
--- a/io/src/main/java/com/itextpdf/io/util/GhostscriptHelper.java
+++ b/io/src/main/java/com/itextpdf/io/util/GhostscriptHelper.java
@@ -47,6 +47,16 @@ This file is part of the iText (R) project.
import java.io.IOException;
+/**
+ * A utility class that is used as an interface to run 3rd-party tool Ghostscript.
+ * Ghostscript is an interpreter for the PostScript language and PDF files, it allows to render them
+ * as images.
+ *
+ *
+ * The Ghostscript needs to be installed independently on the system. This class provides a convenient
+ * way to run it by passing a terminal command. The command can either be specified explicitly or by a mean
+ * of environment variable {@link #GHOSTSCRIPT_ENVIRONMENT_VARIABLE}.
+ */
public class GhostscriptHelper {
/**
* The name of the environment variable with the command to execute Ghostscript operations.
@@ -62,10 +72,19 @@ public class GhostscriptHelper {
private String gsExec;
+ /**
+ * Creates new instance that will rely on Ghostscript execution command defined by {@link
+ * #GHOSTSCRIPT_ENVIRONMENT_VARIABLE} environment variable.
+ */
public GhostscriptHelper() {
this(null);
}
+ /**
+ * Creates new instance that will rely on Ghostscript execution command defined as passed argument.
+ *
+ * @param newGsExec the Ghostscript execution command; if null - environment variables will be used instead
+ */
public GhostscriptHelper(String newGsExec) {
gsExec = newGsExec;
if (gsExec == null) {
@@ -98,10 +117,12 @@ public String getCliExecutionCommand() {
* @param pdf Path to the pdf file.
* @param outDir Path to the output directory
* @param image Path to the generated image
+ *
* @throws IOException if there are file's reading/writing issues
* @throws InterruptedException if there is thread interruption while executing GhostScript.
*/
- public void runGhostScriptImageGeneration(String pdf, String outDir, String image) throws IOException, InterruptedException {
+ public void runGhostScriptImageGeneration(String pdf, String outDir, String image)
+ throws IOException, InterruptedException {
runGhostScriptImageGeneration(pdf, outDir, image, null);
}
@@ -114,13 +135,15 @@ public void runGhostScriptImageGeneration(String pdf, String outDir, String imag
* @param pageList String with numbers of the required pages to extract as image. Should be formatted as string with
* numbers, separated by commas, without whitespaces. Can be null, if it is required to extract
* all pages as images.
+ *
* @throws IOException if there are file's reading/writing issues
* @throws InterruptedException if there is thread interruption while executing GhostScript.
*/
public void runGhostScriptImageGeneration(String pdf, String outDir, String image, String pageList)
throws IOException, InterruptedException {
if (!FileUtil.directoryExists(outDir)) {
- throw new IllegalArgumentException(IoExceptionMessage.CANNOT_OPEN_OUTPUT_DIRECTORY.replace("", pdf));
+ throw new IllegalArgumentException(
+ IoExceptionMessage.CANNOT_OPEN_OUTPUT_DIRECTORY.replace("", pdf));
}
pageList = (pageList == null) ? "" : "-sPageList=".replace("", pageList);
diff --git a/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java b/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java
index f01a20d036..58588158ab 100644
--- a/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java
+++ b/io/src/main/java/com/itextpdf/io/util/ImageMagickHelper.java
@@ -47,6 +47,15 @@ This file is part of the iText (R) project.
import java.io.IOException;
+/**
+ * A utility class that is used as an interface to run 3rd-party tool ImageMagick.
+ * ImageMagick among other things allows to compare images and this class provides means to utilize this feature.
+ *
+ *
+ * The ImageMagick needs to be installed independently on the system. This class provides a convenient
+ * way to run it by passing a terminal command. The command can either be specified explicitly or by a mean
+ * of environment variable {@link #MAGICK_COMPARE_ENVIRONMENT_VARIABLE}.
+ */
public class ImageMagickHelper {
/**
* The name of the environment variable with the command to execute ImageMagic comparison operations.
@@ -60,10 +69,19 @@ public class ImageMagickHelper {
private String compareExec;
+ /**
+ * Creates new instance that will rely on ImageMagick execution command defined by {@link
+ * #MAGICK_COMPARE_ENVIRONMENT_VARIABLE} environment variable.
+ */
public ImageMagickHelper() {
this(null);
}
+ /**
+ * Creates new instance that will rely on ImageMagick execution command defined as passed argument.
+ *
+ * @param newCompareExec the ImageMagick execution command; if null - environment variables will be used instead
+ */
public ImageMagickHelper(String newCompareExec) {
compareExec = newCompareExec;
if (compareExec == null) {
@@ -95,7 +113,9 @@ public String getCliExecutionCommand() {
* @param outImageFilePath Path to the output image file
* @param cmpImageFilePath Path to the cmp image file
* @param diffImageName Path to the difference output image file
+ *
* @return boolean result of comparing: true - images are visually equal
+ *
* @throws IOException if there are file's reading/writing issues
* @throws InterruptedException if there is thread interruption while executing ImageMagick.
*/
@@ -112,13 +132,14 @@ public boolean runImageMagickImageCompare(String outImageFilePath, String cmpIma
* @param diffImageName Path to the difference output image file
* @param fuzzValue String fuzziness value to compare images. Should be formatted as string with integer
* or decimal number. Can be null, if it is not required to use fuzziness
+ *
* @return boolean result of comparing: true - images are visually equal
+ *
* @throws IOException if there are file's reading/writing issues
* @throws InterruptedException if there is thread interruption while executing ImageMagick.
*/
public boolean runImageMagickImageCompare(String outImageFilePath, String cmpImageFilePath,
- String diffImageName, String fuzzValue)
- throws IOException, InterruptedException {
+ String diffImageName, String fuzzValue) throws IOException, InterruptedException {
fuzzValue = (fuzzValue == null) ? "" : " -metric AE -fuzz %".replace("", fuzzValue);
StringBuilder currCompareParams = new StringBuilder();
diff --git a/io/src/test/java/com/itextpdf/io/font/FontCacheNoFontAsianTest.java b/io/src/test/java/com/itextpdf/io/font/FontCacheNoFontAsianTest.java
index add58374b0..eff2ce55b2 100644
--- a/io/src/test/java/com/itextpdf/io/font/FontCacheNoFontAsianTest.java
+++ b/io/src/test/java/com/itextpdf/io/font/FontCacheNoFontAsianTest.java
@@ -43,25 +43,19 @@ This file is part of the iText (R) project.
package com.itextpdf.io.font;
import com.itextpdf.io.IOException;
-import com.itextpdf.io.font.cmap.CMapCidUni;
import com.itextpdf.io.font.otf.Glyph;
-import com.itextpdf.io.util.MessageFormatUtil;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
+
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class FontCacheNoFontAsianTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Before
public void before() {
FontCache.clearSavedFonts();
@@ -151,38 +145,30 @@ public void getRegistryNamesNoFontAsian() {
@Test
public void getCid2UniCMapNoFontAsian() {
- junitExpectedException.expect(IOException.class);
-
// Without font-asian module in the class path
// no CMap can be found.
- FontCache.getCid2UniCmap("UniJIS-UTF16-H");
+ Assert.assertThrows(IOException.class, () -> FontCache.getCid2UniCmap("UniJIS-UTF16-H"));
}
@Test
public void getUni2CidCMapNoFontAsian() {
- junitExpectedException.expect(IOException.class);
-
// Without font-asian module in the class path
// no CMap can be found.
- FontCache.getUni2CidCmap("UniJIS-UTF16-H");
+ Assert.assertThrows(IOException.class, () -> FontCache.getUni2CidCmap("UniJIS-UTF16-H"));
}
@Test
public void getByte2CidCMapNoFontAsian() {
- junitExpectedException.expect(IOException.class);
-
// Without font-asian module in the class path
// no CMap can be found.
- FontCache.getByte2CidCmap("78ms-RKSJ-H");
+ Assert.assertThrows(IOException.class, () -> FontCache.getByte2CidCmap("78ms-RKSJ-H"));
}
@Test
public void getCid2ByteCMapNoFontAsian() {
- junitExpectedException.expect(IOException.class);
-
// Without font-asian module in the class path
// no CMap can be found.
- FontCache.getCid2Byte("78ms-RKSJ-H");
+ Assert.assertThrows(IOException.class, () -> FontCache.getCid2Byte("78ms-RKSJ-H"));
}
private static class FontProgramMock extends FontProgram {
diff --git a/io/src/test/java/com/itextpdf/io/font/FontProgramTest.java b/io/src/test/java/com/itextpdf/io/font/FontProgramTest.java
index 71fe3b3ad2..e30dce695f 100644
--- a/io/src/test/java/com/itextpdf/io/font/FontProgramTest.java
+++ b/io/src/test/java/com/itextpdf/io/font/FontProgramTest.java
@@ -43,32 +43,28 @@ This file is part of the iText (R) project.
package com.itextpdf.io.font;
import com.itextpdf.io.font.constants.StandardFonts;
+import com.itextpdf.io.util.MessageFormatUtil;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
+
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
-
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
-import com.itextpdf.io.util.MessageFormatUtil;
@Category(UnitTest.class)
public class FontProgramTest extends ExtendedITextTest {
private static final String notExistingFont = "some-font.ttf";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void exceptionMessageTest() throws IOException {
- junitExpectedException.expect(java.io.IOException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(com.itextpdf.io.IOException._1NotFoundAsFileOrResource, notExistingFont));
- FontProgramFactory.createFont(notExistingFont);
+ Exception e = Assert.assertThrows(java.io.IOException.class,
+ () -> FontProgramFactory.createFont(notExistingFont)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(com.itextpdf.io.IOException._1NotFoundAsFileOrResource, notExistingFont), e.getMessage());
}
@Test
diff --git a/io/src/test/java/com/itextpdf/io/image/GifTest.java b/io/src/test/java/com/itextpdf/io/image/GifTest.java
index c7897a31d7..cfd68613ac 100644
--- a/io/src/test/java/com/itextpdf/io/image/GifTest.java
+++ b/io/src/test/java/com/itextpdf/io/image/GifTest.java
@@ -52,18 +52,13 @@ This file is part of the iText (R) project.
import java.io.FileInputStream;
import java.util.List;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class GifTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/io/image/GifTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void gifImageTest() throws IOException, java.io.IOException {
try (FileInputStream file = new FileInputStream(sourceFolder + "WP_20140410_001.gif")) {
@@ -76,9 +71,9 @@ public void gifImageTest() throws IOException, java.io.IOException {
@Test
public void gifImageFrameOutOfBoundsTest() throws java.io.IOException {
- junitExpectedException.expect(IOException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(IOException.CannotFind1Frame, 2));
- ImageDataFactory.createGifFrame(UrlUtil.toURL(sourceFolder + "image-2frames.gif"), 3);
+ Exception e = Assert.assertThrows(IOException.class,
+ () -> ImageDataFactory.createGifFrame(UrlUtil.toURL(sourceFolder + "image-2frames.gif"), 3));
+ Assert.assertEquals(MessageFormatUtil.format(IOException.CannotFind1Frame, 2), e.getMessage());
}
@Test
diff --git a/io/src/test/java/com/itextpdf/io/image/ImageTypeDetectorTest.java b/io/src/test/java/com/itextpdf/io/image/ImageTypeDetectorTest.java
index 41d242be1e..a75837c58b 100644
--- a/io/src/test/java/com/itextpdf/io/image/ImageTypeDetectorTest.java
+++ b/io/src/test/java/com/itextpdf/io/image/ImageTypeDetectorTest.java
@@ -22,10 +22,15 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.io.image;
+import com.itextpdf.io.util.StreamUtil;
import com.itextpdf.io.util.UrlUtil;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Assert;
@@ -39,32 +44,113 @@ public class ImageTypeDetectorTest extends ExtendedITextTest {
private static final String IMAGE_NAME = "image";
@Test
- public void testUnknown() throws MalformedURLException {
- test(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".txt"), ImageType.NONE);
+ public void testUrlUnknown() throws MalformedURLException {
+ testURL(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".txt"), ImageType.NONE);
}
@Test
- public void testGif() throws MalformedURLException {
- test(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".gif"), ImageType.GIF);
+ public void testUrlGif() throws MalformedURLException {
+ testURL(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".gif"), ImageType.GIF);
}
@Test
- public void testJpeg() throws MalformedURLException {
- test(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".jpg"), ImageType.JPEG);
+ public void testUrlJpeg() throws MalformedURLException {
+ testURL(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".jpg"), ImageType.JPEG);
}
@Test
- public void testTiff() throws MalformedURLException {
- test(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".tiff"), ImageType.TIFF);
+ public void testUrlTiff() throws MalformedURLException {
+ testURL(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".tiff"), ImageType.TIFF);
}
@Test
- public void testWmf() throws MalformedURLException {
- test(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".wmf"), ImageType.WMF);
+ public void testUrlWmf() throws MalformedURLException {
+ testURL(UrlUtil.toURL(SOURCE_FOLDER + IMAGE_NAME + ".wmf"), ImageType.WMF);
}
- private void test(URL location, ImageType expectedType) {
+ @Test
+ public void testNullUrl() throws MalformedURLException {
+ URL url = UrlUtil.toURL("not existing path");
+
+ Assert.assertThrows(com.itextpdf.io.IOException.class,
+ () -> ImageTypeDetector.detectImageType(url)
+ );
+ }
+
+ @Test
+ public void testStreamUnknown() throws FileNotFoundException {
+ testStream(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".txt"), ImageType.NONE);
+ }
+
+ @Test
+ public void testStreamGif() throws FileNotFoundException {
+ testStream(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".gif"), ImageType.GIF);
+ }
+
+ @Test
+ public void testStreamJpeg() throws FileNotFoundException {
+ testStream(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".jpg"), ImageType.JPEG);
+ }
+
+ @Test
+ public void testStreamTiff() throws FileNotFoundException {
+ testStream(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".tiff"), ImageType.TIFF);
+ }
+
+ @Test
+ public void testStreamWmf() throws FileNotFoundException {
+ testStream(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".wmf"), ImageType.WMF);
+ }
+
+ @Test
+ public void testStreamClosed() throws IOException {
+ InputStream stream = new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".wmf");
+ stream.close();
+
+ // A common exception is expected instead of com.itextpdf.io.IOException, because in .NET
+ // the thrown exception is different
+ Assert.assertThrows(Exception.class, () -> ImageTypeDetector.detectImageType(stream));
+ }
+
+ @Test
+ public void testBytesUnknown() throws IOException {
+ testBytes(StreamUtil.inputStreamToArray(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".txt")),
+ ImageType.NONE);
+ }
+
+ @Test
+ public void testBytesGif() throws IOException {
+ testBytes(StreamUtil.inputStreamToArray(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".gif")),
+ ImageType.GIF);
+ }
+
+ @Test
+ public void testBytesJpeg() throws IOException {
+ testBytes(StreamUtil.inputStreamToArray(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".jpg")),
+ ImageType.JPEG);
+ }
+
+ @Test
+ public void testBytesTiff() throws IOException {
+ testBytes(StreamUtil.inputStreamToArray(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".tiff")),
+ ImageType.TIFF);
+ }
+
+ @Test
+ public void testBytesWmf() throws IOException {
+ testBytes(StreamUtil.inputStreamToArray(new FileInputStream(SOURCE_FOLDER + IMAGE_NAME + ".wmf")),
+ ImageType.WMF);
+ }
+
+ private static void testURL(URL location, ImageType expectedType) {
Assert.assertEquals(expectedType, ImageTypeDetector.detectImageType(location));
}
+ private static void testStream(InputStream stream, ImageType expectedType) {
+ Assert.assertEquals(expectedType, ImageTypeDetector.detectImageType(stream));
+ }
+
+ private static void testBytes(byte[] bytes, ImageType expectedType) {
+ Assert.assertEquals(expectedType, ImageTypeDetector.detectImageType(bytes));
+ }
}
diff --git a/io/src/test/java/com/itextpdf/io/source/PdfTokenizerTest.java b/io/src/test/java/com/itextpdf/io/source/PdfTokenizerTest.java
index bef403a50f..0e81b59197 100644
--- a/io/src/test/java/com/itextpdf/io/source/PdfTokenizerTest.java
+++ b/io/src/test/java/com/itextpdf/io/source/PdfTokenizerTest.java
@@ -50,18 +50,13 @@ This file is part of the iText (R) project.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import static com.itextpdf.io.IOException.ErrorAtFilePointer1;
@Category(UnitTest.class)
public class PdfTokenizerTest extends ExtendedITextTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
private static final String sourceFolder = "./src/test/resources/com/itextpdf/io/util/";
@Test
@@ -262,14 +257,14 @@ public void getDecodedStringContentHexTest() throws IOException {
@Test
public void throwErrorTest() {
- expectedException.expect(com.itextpdf.io.IOException.class);
- expectedException.expectMessage(MessageFormatUtil.format(ErrorAtFilePointer1, 0));
-
RandomAccessSourceFactory factory = new RandomAccessSourceFactory();
PdfTokenizer tok = new PdfTokenizer(new RandomAccessFileOrArray(
factory.createSource("/Name1".getBytes(StandardCharsets.ISO_8859_1))));
- tok.throwError(ErrorAtFilePointer1, 0);
+ Exception e = Assert.assertThrows(com.itextpdf.io.IOException.class,
+ () -> tok.throwError(ErrorAtFilePointer1, 0)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(ErrorAtFilePointer1, 0), e.getMessage());
}
@Test
diff --git a/io/src/test/java/com/itextpdf/io/source/RAFRandomAccessSourceTest.java b/io/src/test/java/com/itextpdf/io/source/RAFRandomAccessSourceTest.java
index 756e055683..ae06bfe4f3 100644
--- a/io/src/test/java/com/itextpdf/io/source/RAFRandomAccessSourceTest.java
+++ b/io/src/test/java/com/itextpdf/io/source/RAFRandomAccessSourceTest.java
@@ -47,22 +47,16 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.UnitTest;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class RAFRandomAccessSourceTest extends ExtendedITextTest {
private final static String SOURCE_FILE = "./src/test/resources/com/itextpdf/io/source/RAF.txt";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
private final byte[] content = "Hello, world!".getBytes();
@Test
diff --git a/io/src/test/java/com/itextpdf/io/util/GhostscriptHelperTest.java b/io/src/test/java/com/itextpdf/io/util/GhostscriptHelperTest.java
index 1d7628ae10..5f7a768c96 100644
--- a/io/src/test/java/com/itextpdf/io/util/GhostscriptHelperTest.java
+++ b/io/src/test/java/com/itextpdf/io/util/GhostscriptHelperTest.java
@@ -45,28 +45,23 @@ This file is part of the iText (R) project.
import com.itextpdf.io.IoExceptionMessage;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
-
import java.io.File;
import java.io.IOException;
@Category(IntegrationTest.class)
public class GhostscriptHelperTest extends ExtendedITextTest {
- private final static String sourceFolder = "./src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/";
- private static final String destinationFolder = "./target/test/com/itextpdf/io/GhostscriptHelperTest/";
-
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
+ private final static String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/";
+ private static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/io/GhostscriptHelperTest/";
@Before
public void setUp() {
- createOrClearDestinationFolder(destinationFolder);
+ createOrClearDestinationFolder(DESTINATION_FOLDER);
}
@Test
@@ -96,136 +91,111 @@ public void ghostScriptEnvVarIsNull() {
@Test
public void ghostScriptEnvVarIsIncorrect() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage(IoExceptionMessage.GS_ENVIRONMENT_VARIABLE_IS_NOT_SPECIFIED);
-
- GhostscriptHelper ghostscriptHelper = new GhostscriptHelper("-");
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new GhostscriptHelper("-")
+ );
+ Assert.assertEquals(IoExceptionMessage.GS_ENVIRONMENT_VARIABLE_IS_NOT_SPECIFIED, e.getMessage());
}
@Test
public void runGhostScriptIncorrectOutputDirectory() throws IOException, InterruptedException {
- String inputPdf = sourceFolder + "imageHandlerUtilTest.pdf";
+ String inputPdf = SOURCE_FOLDER + "imageHandlerUtilTest.pdf";
String exceptionMessage = "Cannot open output directory for " + inputPdf;
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage(exceptionMessage);
-
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
- ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, "-",
- "outputPageImage.png", "1");
+
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, "-",
+ "outputPageImage.png", "1")
+ );
+ Assert.assertEquals(exceptionMessage, e.getMessage());
}
@Test
public void runGhostScriptIncorrectParams() throws IOException, InterruptedException {
- String inputPdf = sourceFolder + "imageHandlerUtilTest.pdf";
+ String inputPdf = SOURCE_FOLDER + "imageHandlerUtilTest.pdf";
String exceptionMessage = "GhostScript failed for " + inputPdf;
- junitExpectedException.expect(GhostscriptHelper.GhostscriptExecutionException.class);
- junitExpectedException.expectMessage(exceptionMessage);
-
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
- ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, destinationFolder,
- "outputPageImage.png", "q@W");
+
+ Exception e = Assert.assertThrows(GhostscriptHelper.GhostscriptExecutionException.class,
+ () -> ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, DESTINATION_FOLDER,
+ "outputPageImage.png", "q@W")
+ );
+ Assert.assertEquals(exceptionMessage, e.getMessage());
}
@Test
public void runGhostScriptTestForSpecificPage() throws IOException, InterruptedException {
- String inputPdf = sourceFolder + "imageHandlerUtilTest.pdf";
+ String inputPdf = SOURCE_FOLDER + "imageHandlerUtilTest.pdf";
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
- ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, destinationFolder,
+ ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, DESTINATION_FOLDER,
"specificPage.png", "1");
- Assert.assertEquals(1, FileUtil.listFilesInDirectory(destinationFolder, true).length);
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "specificPage.png"));
+ Assert.assertEquals(1, FileUtil.listFilesInDirectory(DESTINATION_FOLDER, true).length);
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "specificPage.png"));
}
@Test
public void runGhostScriptTestForSeveralSpecificPages() throws IOException, InterruptedException {
- String inputPdf = sourceFolder + "imageHandlerUtilTest.pdf";
+ String inputPdf = SOURCE_FOLDER + "imageHandlerUtilTest.pdf";
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
String imageFileName = new File(inputPdf).getName() + "_severalSpecificPages-%03d.png";
- ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, destinationFolder,
+ ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, DESTINATION_FOLDER,
imageFileName, "1,3");
- Assert.assertEquals(2, FileUtil.listFilesInDirectory(destinationFolder, true).length);
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "imageHandlerUtilTest.pdf_severalSpecificPages-001.png"));
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "imageHandlerUtilTest.pdf_severalSpecificPages-002.png"));
+ Assert.assertEquals(2, FileUtil.listFilesInDirectory(DESTINATION_FOLDER, true).length);
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "imageHandlerUtilTest.pdf_severalSpecificPages-001.png"));
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "imageHandlerUtilTest.pdf_severalSpecificPages-002.png"));
}
@Test
public void runGhostScriptTestForAllPages() throws IOException, InterruptedException {
- String inputPdf = sourceFolder + "imageHandlerUtilTest.pdf";
+ String inputPdf = SOURCE_FOLDER + "imageHandlerUtilTest.pdf";
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
String imageFileName = new File(inputPdf).getName() + "_allPages-%03d.png";
- ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, destinationFolder, imageFileName);
+ ghostscriptHelper.runGhostScriptImageGeneration(inputPdf, DESTINATION_FOLDER, imageFileName);
- Assert.assertEquals(3, FileUtil.listFilesInDirectory(destinationFolder, true).length);
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "imageHandlerUtilTest.pdf_allPages-001.png"));
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "imageHandlerUtilTest.pdf_allPages-002.png"));
- Assert.assertTrue(FileUtil.fileExists(destinationFolder + "imageHandlerUtilTest.pdf_allPages-003.png"));
+ Assert.assertEquals(3, FileUtil.listFilesInDirectory(DESTINATION_FOLDER, true).length);
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "imageHandlerUtilTest.pdf_allPages-001.png"));
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "imageHandlerUtilTest.pdf_allPages-002.png"));
+ Assert.assertTrue(FileUtil.fileExists(DESTINATION_FOLDER + "imageHandlerUtilTest.pdf_allPages-003.png"));
}
@Test
public void dSaferParamInGhostScriptHelperTest() throws IOException, InterruptedException {
- String cmpPdf = sourceFolder + "maliciousPsInvokingCalcExe.ps";
- String maliciousPsInvokingCalcExe = destinationFolder + "maliciousPsInvokingCalcExe.png";
- int majorVersion = 0;
- int minorVersion = 0;
- boolean isWindows = identifyOsType().toLowerCase().contains("win");
- if (isWindows) {
- String gsExec = SystemUtil.getPropertyOrEnvironmentVariable(GhostscriptHelper.GHOSTSCRIPT_ENVIRONMENT_VARIABLE);
- if (gsExec == null) {
- gsExec = SystemUtil.getPropertyOrEnvironmentVariable(GhostscriptHelper.GHOSTSCRIPT_ENVIRONMENT_VARIABLE_LEGACY);
- }
- String[] pathParts = gsExec.split("\\d\\.\\d\\d");
- for (int i = 0; i < pathParts.length; i++) {
- gsExec = gsExec.replace(pathParts[i], "");
- }
- String[] version = gsExec.split("\\.");
- majorVersion = Integer.parseInt(version[0]);
- minorVersion = Integer.parseInt(version[1]);
- }
+ String input = SOURCE_FOLDER + "unsafePostScript.ps";
+ String outputName = "unsafePostScript.png";
+ String maliciousResult1 = DESTINATION_FOLDER + "output1.txt";
+ String maliciousResult2 = DESTINATION_FOLDER + "output2.txt";
try {
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
- ghostscriptHelper.runGhostScriptImageGeneration(cmpPdf, destinationFolder, "maliciousPsInvokingCalcExe.png");
- if (isWindows) {
- Assert.assertTrue((majorVersion > 9 || (majorVersion == 9 && minorVersion >= 50)));
- }
+ ghostscriptHelper.runGhostScriptImageGeneration(input, DESTINATION_FOLDER, outputName);
} catch (GhostscriptHelper.GhostscriptExecutionException e) {
- if (isWindows) {
- Assert.assertTrue((majorVersion < 9 || (majorVersion == 9 && minorVersion < 50)));
- }
+ System.out.println("Error code was returned on processing of malicious script with -dSAFER option enabled. "
+ + "This is expected for some environments and ghostscript versions. "
+ + "We assert only the absence of malicious script result (created file).\n");
}
- Assert.assertFalse(FileUtil.fileExists(maliciousPsInvokingCalcExe));
+ Assert.assertFalse(FileUtil.fileExists(maliciousResult1));
+ Assert.assertFalse(FileUtil.fileExists(maliciousResult2));
}
@Test
public void ghostScriptImageGenerationTest() throws IOException, InterruptedException {
String filename = "resultantImage.png";
- String psFile = sourceFolder + "simple.ps";
- String resultantImage = destinationFolder + filename;
- String cmpResultantImage = sourceFolder + "cmp_" + filename;
- String diff = destinationFolder + "diff_" + filename;
+ String psFile = SOURCE_FOLDER + "simple.ps";
+ String resultantImage = DESTINATION_FOLDER + filename;
+ String cmpResultantImage = SOURCE_FOLDER + "cmp_" + filename;
+ String diff = DESTINATION_FOLDER + "diff_" + filename;
GhostscriptHelper ghostscriptHelper = new GhostscriptHelper();
- ghostscriptHelper.runGhostScriptImageGeneration(psFile, destinationFolder, filename);
+ ghostscriptHelper.runGhostScriptImageGeneration(psFile, DESTINATION_FOLDER, filename);
Assert.assertTrue(FileUtil.fileExists(resultantImage));
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
Assert.assertTrue(imageMagickHelper.runImageMagickImageCompare(resultantImage, cmpResultantImage, diff));
}
-
- /**
- * Identifies type of current OS and return it (win, linux).
- *
- * @return type of current os as {@link java.lang.String}
- */
- private static String identifyOsType() {
- String os = System.getProperty("os.name") == null
- ? System.getProperty("OS") : System.getProperty("os.name");
- return os.toLowerCase();
- }
}
diff --git a/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java b/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java
index 2e31959b6f..e71cfdb03e 100644
--- a/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java
+++ b/io/src/test/java/com/itextpdf/io/util/ImageMagickHelperTest.java
@@ -45,26 +45,21 @@ This file is part of the iText (R) project.
import com.itextpdf.io.IoExceptionMessage;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
-
import java.io.IOException;
@Category(IntegrationTest.class)
public class ImageMagickHelperTest extends ExtendedITextTest {
- private final static String sourceFolder = "./src/test/resources/com/itextpdf/io/util/ImageMagickHelperTest/";
- private static final String destinationFolder = "./target/test/com/itextpdf/io/ImageMagickHelperTest/";
-
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
+ private final static String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/io/util/ImageMagickHelperTest/";
+ private static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/io/ImageMagickHelperTest/";
@Before
public void setUp() {
- createOrClearDestinationFolder(destinationFolder);
+ createOrClearDestinationFolder(DESTINATION_FOLDER);
}
@Test
@@ -87,9 +82,9 @@ public void imageMagickEnvVarIsExplicitlySpecified() {
@Test
public void imageMagickEnvVarIsNull() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "image.png";
- String cmpImage = sourceFolder + "cmp_image.png";
- String diff = destinationFolder + "diff.png";
+ String inputImage = SOURCE_FOLDER + "image.png";
+ String cmpImage = SOURCE_FOLDER + "cmp_image.png";
+ String diff = DESTINATION_FOLDER + "diff.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper(null);
boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff);
@@ -100,17 +95,17 @@ public void imageMagickEnvVarIsNull() throws IOException, InterruptedException {
@Test
public void imageMagickEnvVarIsIncorrect() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage(IoExceptionMessage.COMPARE_COMMAND_SPECIFIED_INCORRECTLY);
-
- ImageMagickHelper imageMagickHelper = new ImageMagickHelper("-");
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new ImageMagickHelper("-")
+ );
+ Assert.assertEquals(IoExceptionMessage.COMPARE_COMMAND_SPECIFIED_INCORRECTLY, e.getMessage());
}
@Test
public void runImageMagickForEqualImages() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "image.png";
- String cmpImage = sourceFolder + "cmp_image.png";
- String diff = destinationFolder + "diff_equalImages.png";
+ String inputImage = SOURCE_FOLDER + "image.png";
+ String cmpImage = SOURCE_FOLDER + "cmp_image.png";
+ String diff = DESTINATION_FOLDER + "diff_equalImages.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff);
@@ -121,9 +116,9 @@ public void runImageMagickForEqualImages() throws IOException, InterruptedExcept
@Test
public void runImageMagickForEqualImagesWithFuzzParam() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "image.png";
- String cmpImage = sourceFolder + "cmp_image.png";
- String diff = destinationFolder + "diff_equalImagesFuzzParam.png";
+ String inputImage = SOURCE_FOLDER + "image.png";
+ String cmpImage = SOURCE_FOLDER + "cmp_image.png";
+ String diff = DESTINATION_FOLDER + "diff_equalImagesFuzzParam.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff, "0.5");
@@ -134,9 +129,9 @@ public void runImageMagickForEqualImagesWithFuzzParam() throws IOException, Inte
@Test
public void runImageMagickForDifferentImages() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "Im1_1.jpg";
- String cmpImage = sourceFolder + "cmp_Im1_1.jpg";
- String diff = destinationFolder + "diff_differentImages.png";
+ String inputImage = SOURCE_FOLDER + "Im1_1.jpg";
+ String cmpImage = SOURCE_FOLDER + "cmp_Im1_1.jpg";
+ String diff = DESTINATION_FOLDER + "diff_differentImages.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff);
@@ -147,9 +142,9 @@ public void runImageMagickForDifferentImages() throws IOException, InterruptedEx
@Test
public void runImageMagickForDifferentImagesWithFuzzParamNotEqual() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "Im1_1.jpg";
- String cmpImage = sourceFolder + "cmp_Im1_1.jpg";
- String diff = destinationFolder + "diff_differentImagesFuzzNotEnough.png";
+ String inputImage = SOURCE_FOLDER + "Im1_1.jpg";
+ String cmpImage = SOURCE_FOLDER + "cmp_Im1_1.jpg";
+ String diff = DESTINATION_FOLDER + "diff_differentImagesFuzzNotEnough.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff, "0.1");
@@ -160,12 +155,12 @@ public void runImageMagickForDifferentImagesWithFuzzParamNotEqual() throws IOExc
@Test
public void runImageMagickForDifferentImagesWithFuzzParamEqual() throws IOException, InterruptedException {
- String inputImage = sourceFolder + "Im1_1.jpg";
- String cmpImage = sourceFolder + "cmp_Im1_1.jpg";
- String diff = destinationFolder + "diff_differentImagesFuzzEnough.png";
+ String inputImage = SOURCE_FOLDER + "Im1_1.jpg";
+ String cmpImage = SOURCE_FOLDER + "cmp_Im1_1.jpg";
+ String diff = DESTINATION_FOLDER + "diff_differentImagesFuzzEnough.png";
ImageMagickHelper imageMagickHelper = new ImageMagickHelper();
- boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff, "1.2");
+ boolean result = imageMagickHelper.runImageMagickImageCompare(inputImage, cmpImage, diff, "2.1");
Assert.assertTrue(result);
Assert.assertTrue(FileUtil.fileExists(diff));
diff --git a/io/src/test/java/com/itextpdf/io/util/MatcherTest.java b/io/src/test/java/com/itextpdf/io/util/MatcherTest.java
index 352a2d5f48..3b7b8e5aec 100644
--- a/io/src/test/java/com/itextpdf/io/util/MatcherTest.java
+++ b/io/src/test/java/com/itextpdf/io/util/MatcherTest.java
@@ -28,10 +28,8 @@ This file is part of the iText (R) project.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
/**
* At the moment there is no com.itextpdf.io.util.Matcher class in Java (as we use
@@ -44,9 +42,6 @@ public class MatcherTest extends ExtendedITextTest {
private static final Pattern PATTERN = Pattern.compile(PATTERN_STRING);
private static final Pattern FULL_MATCH_PATTERN = Pattern.compile("^" + PATTERN_STRING + "$");
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void matchesTest() {
Matcher matched = FULL_MATCH_PATTERN.matcher("aaabbb");
@@ -94,8 +89,7 @@ public void twoGroupsFindWithIndexTest() {
public void startBeforeSearchTest() {
Matcher matcher = PATTERN.matcher("aabb");
- junitExpectedException.expect(IllegalStateException.class);
- matcher.start();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.start());
}
@Test
@@ -104,16 +98,15 @@ public void startWhenFindFailsTest() {
while (matcher.find()) {
}
- junitExpectedException.expect(IllegalStateException.class);
- matcher.start();
+
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.start());
}
@Test
public void endBeforeSearchTest() {
Matcher matcher = PATTERN.matcher("aabb");
- junitExpectedException.expect(IllegalStateException.class);
- matcher.end();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.end());
}
@Test
@@ -122,16 +115,15 @@ public void endWhenFindFailsTest() {
while (matcher.find()) {
}
- junitExpectedException.expect(IllegalStateException.class);
- matcher.end();
+
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.end());
}
@Test
public void groupBeforeSearchTest() {
Matcher matcher = PATTERN.matcher("aabb");
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group());
}
@Test
@@ -140,16 +132,15 @@ public void groupWhenFindFailsTest() {
while (matcher.find()) {
}
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group();
+
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group());
}
@Test
public void groupWithIndexBeforeSearchTest() {
Matcher matcher = PATTERN.matcher("aabb");
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group(0);
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group(0));
}
@Test
@@ -158,8 +149,8 @@ public void groupWithIndexWhenFindFailsTest() {
while (matcher.find()) {
}
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group(0);
+
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group(0));
}
@Test
@@ -167,8 +158,7 @@ public void groupNegativeIndexTest() {
Matcher matcher = PATTERN.matcher("aabb");
Assert.assertTrue(matcher.find());
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.group(-1);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.group(-1));
}
@Test
@@ -176,16 +166,14 @@ public void groupIndexGraterThanGroupCountTest() {
Matcher matcher = PATTERN.matcher("aabb");
Assert.assertTrue(matcher.find());
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.group(3);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.group(3));
}
@Test
public void findNegativeIndexTest() {
Matcher matcher = PATTERN.matcher("aabb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(-1);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(-1));
}
@Test
@@ -193,8 +181,7 @@ public void findIndexGraterThanInputLengthTest() {
String input = "aabb";
Matcher matcher = PATTERN.matcher(input);
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(input.length() + 1);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(input.length() + 1));
}
@Test
@@ -261,8 +248,7 @@ public void groupOutOfBoundsTest() {
Assert.assertEquals("123", matcher.group(0));
Assert.assertEquals("123", matcher.group(1));
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.group(2);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.group(2));
}
@Test
@@ -272,8 +258,7 @@ public void groupWhenNoMatchTest() {
Matcher matcher = Pattern.compile(testPattern).matcher(input);
Assert.assertFalse(matcher.find());
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group(0);
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group(0));
}
@Test
@@ -305,10 +290,9 @@ public void startIndexNotFoundTest() {
String testPattern = "ef";
String input = "abcde";
Matcher matcher = Pattern.compile(testPattern).matcher(input);
- Assert.assertFalse(matcher.find());
- junitExpectedException.expect(IllegalStateException.class);
- matcher.start();
+ Assert.assertFalse(matcher.find());
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.start());
}
@Test
@@ -316,10 +300,9 @@ public void endIndexNotFoundTest() {
String testPattern = "ef";
String input = "abcde";
Matcher matcher = Pattern.compile(testPattern).matcher(input);
- Assert.assertFalse(matcher.find());
- junitExpectedException.expect(IllegalStateException.class);
- matcher.end();
+ Assert.assertFalse(matcher.find());
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.end());
}
@Test
@@ -376,8 +359,7 @@ public void findMatchStartingFromIndexOutOfBoundsTest() {
int startIndex = 4;
Matcher matcher = Pattern.compile(testPattern).matcher(input);
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(startIndex);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(startIndex));
}
@Test
@@ -389,8 +371,8 @@ public void findNextMatchStartingFromIndexOutOfBoundsTest() {
Assert.assertTrue(matcher.find());
int startIndex = 4;
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(startIndex);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(startIndex));
}
@Test
@@ -400,8 +382,7 @@ public void findMatchStartingFromNegativeIndexTest() {
int startIndex = -1;
Matcher matcher = Pattern.compile(testPattern).matcher(input);
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(startIndex);
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(startIndex));
}
@Test
@@ -413,8 +394,8 @@ public void findNextMatchStartingFromNegativeIndexTest() {
Assert.assertTrue(matcher.find());
int startIndex = -1;
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.find(startIndex);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.find(startIndex));
}
@Test
@@ -552,36 +533,36 @@ public void stringMatchesButRegionDoesNotMatchTest() {
@Test
public void negativeStartOfRegionTest() {
Matcher matcher = PATTERN.matcher("abbbbbbbbbbbbbbbbbbbbb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.region(-1, 10);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.region(-1, 10));
}
@Test
public void tooLargeStartOfRegionTest() {
Matcher matcher = PATTERN.matcher("abbbbbbbbbbbbbbbbbbbbb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.region(24, 24);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.region(24, 24));
}
@Test
public void negativeEndOfRegionTest() {
Matcher matcher = PATTERN.matcher("abbbbbbbbbbbbbbbbbbbbb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.region(1, -1);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.region(1, -1));
}
@Test
public void tooLargeEndOfRegionTest() {
Matcher matcher = PATTERN.matcher("abbbbbbbbbbbbbbbbbbbbb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.region(1, 24);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.region(1, 24));
}
@Test
public void endGreaterThenStartRegionTest() {
Matcher matcher = PATTERN.matcher("abbbbbbbbbbbbbbbbbbbbb");
- junitExpectedException.expect(IndexOutOfBoundsException.class);
- matcher.region(10, 9);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> matcher.region(10, 9));
}
@Test
@@ -644,8 +625,7 @@ public void startRegionDoesNotMatchesTest() {
matcher.region(6, 13);
Assert.assertFalse(matcher.find());
- junitExpectedException.expect(IllegalStateException.class);
- matcher.start();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.start());
}
@Test
@@ -654,8 +634,7 @@ public void endRegionDoesNotMatchesTest() {
matcher.region(6, 13);
Assert.assertFalse(matcher.find());
- junitExpectedException.expect(IllegalStateException.class);
- matcher.end();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.end());
}
@Test
@@ -706,8 +685,7 @@ public void startAfterRegionThrowsExceptionTest() {
matcher.find();
matcher.region(6, 13);
- junitExpectedException.expect(IllegalStateException.class);
- matcher.start();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.start());
}
@Test
@@ -716,8 +694,7 @@ public void endAfterRegionThrowsExceptionTest() {
matcher.find();
matcher.region(6, 13);
- junitExpectedException.expect(IllegalStateException.class);
- matcher.end();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.end());
}
@Test
@@ -726,8 +703,7 @@ public void groupAfterRegionThrowsExceptionTest() {
matcher.find();
matcher.region(6, 13);
- junitExpectedException.expect(IllegalStateException.class);
- matcher.group();
+ Assert.assertThrows(IllegalStateException.class, () -> matcher.group());
}
}
diff --git a/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/maliciousPsInvokingCalcExe.ps b/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/maliciousPsInvokingCalcExe.ps
deleted file mode 100644
index c7790c1cdc..0000000000
Binary files a/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/maliciousPsInvokingCalcExe.ps and /dev/null differ
diff --git a/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/unsafePostScript.ps b/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/unsafePostScript.ps
new file mode 100644
index 0000000000..7b4444ca49
Binary files /dev/null and b/io/src/test/resources/com/itextpdf/io/util/GhostscriptHelperTest/unsafePostScript.ps differ
diff --git a/itextcore/pom.xml b/itextcore/pom.xml
index 99aedc13bd..1130598a07 100644
--- a/itextcore/pom.xml
+++ b/itextcore/pom.xml
@@ -3,7 +3,7 @@
4.0.0com.itextpdfitext7-core
- 7.1.15
+ 7.1.16pomiText 7 CoreA Free Java-PDF library
@@ -134,16 +134,4 @@
${project.version}
-
-
-
- com.github.spotbugs
- spotbugs-maven-plugin
- 3.1.11
-
- true
-
-
-
-
-
\ No newline at end of file
+
diff --git a/kernel/pom.xml b/kernel/pom.xml
index 341718a4e8..425a8687d9 100644
--- a/kernel/pom.xml
+++ b/kernel/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16kerneliText 7 - kernel
diff --git a/kernel/src/main/java/com/itextpdf/kernel/KernelLogMessageConstant.java b/kernel/src/main/java/com/itextpdf/kernel/KernelLogMessageConstant.java
index 77fb2e2f6b..a4dddff731 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/KernelLogMessageConstant.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/KernelLogMessageConstant.java
@@ -51,6 +51,9 @@ public final class KernelLogMessageConstant {
public static final String DCTDECODE_FILTER_DECODING = "DCTDecode filter decoding into the "
+ "bit map is not supported. The stream data would be left in JPEG baseline format";
+ public static final String FEATURE_IS_NOT_SUPPORTED =
+ "Exception was thrown: {0}. The feature {1} is probably not supported by your XML processor.";
+
public static final String FULL_COMPRESSION_APPEND_MODE_XREF_TABLE_INCONSISTENCY = "Full compression mode requested "
+ "in append mode but the original document has cross-reference table, not cross-reference stream. "
+ "Falling back to cross-reference table in appended document and switching full compression off";
diff --git a/kernel/src/main/java/com/itextpdf/kernel/PdfException.java b/kernel/src/main/java/com/itextpdf/kernel/PdfException.java
index c43242b0b5..0d6c5e1db2 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/PdfException.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/PdfException.java
@@ -168,6 +168,8 @@ public class PdfException extends RuntimeException {
public static final String EncryptedPayloadFileSpecShallHaveTypeEqualToFilespec = "Encrypted payload file spec shall have 'Type' key. The value of such key shall be 'Filespec'.";
public static final String EncryptedPayloadShallHaveTypeEqualsToEncryptedPayloadIfPresent = "Encrypted payload dictionary shall have field 'Type' equal to 'EncryptedPayload' if present";
public static final String EncryptedPayloadShallHaveSubtype = "Encrypted payload shall have 'Subtype' field specifying crypto filter";
+ public static final String ExternalEntityElementFoundInXml =
+ "External entity element found in XML. This entity will not be parsed to prevent XML attacks.";
public static final String FailedToGetTsaResponseFrom1 = "Failed to get TSA response from {0}.";
public static final String FieldFlatteningIsNotSupportedInAppendMode = "Field flattening is not supported in append mode.";
diff --git a/kernel/src/main/java/com/itextpdf/kernel/Version.java b/kernel/src/main/java/com/itextpdf/kernel/Version.java
index e8b7ac60cf..8fd945bafb 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/Version.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/Version.java
@@ -78,7 +78,7 @@ public final class Version {
* This String contains the version number of this iText release.
* For debugging purposes, we request you NOT to change this constant.
*/
- private static final String release = "7.1.15";
+ private static final String release = "7.1.16";
/**
* This String contains the iText version as shown in the producer line.
* iText is a product developed by iText Group NV.
@@ -109,27 +109,31 @@ public Version() {
/**
* Gets an instance of the iText version that is currently used.
+ *
*
* Note that iText Group requests that you retain the iText producer line
* in every PDF that is created or manipulated using iText.
* @return an instance of {@link Version}.
*/
public static Version getInstance() {
- synchronized (staticLock) {
- if (version != null) {
- try {
- licenseScheduledCheck();
- } catch (Exception e) {
- // If any exception occurs during scheduled check of core license,
- // then it means that license is not valid yet, so roll back to AGPL.
- // The key value is null as it is similar to case
- // when an exception has been thrown during initial license loading
- atomicSetVersion(initAGPLVersion(e, null));
- }
- return version;
+ Version localVersion = version;
+ // It's crucial to work with 'localVersion' local variable, because 'version' field can be
+ // changed by some other thread. We also don't want to block Version class lock when calling
+ // for scheduled check in order to avoid synchronization issues with parallel loading license.
+ if (localVersion != null) {
+ try {
+ licenseScheduledCheck(localVersion);
+ return localVersion;
+ } catch (Exception e) {
+ // If any exception occurs during scheduled check of core license it means that
+ // license is not valid, in this particular case we want to reset to AGPL Version,
+ // however "normal" initialization logic will not switch to AGPL unless license is
+ // unloaded.
+
+ // not saving this AGPL version in order to avoid race condition with loaded proper license
+ return initAGPLVersion(e, null);
}
}
- Version localVersion;
String key = null;
try {
String coreVersion = release;
@@ -386,8 +390,8 @@ private static Version atomicSetVersion(Version newVersion) {
}
}
- private static void licenseScheduledCheck() {
- if (version.isAGPL()) {
+ private static void licenseScheduledCheck(Version localVersion) {
+ if (localVersion.isAGPL()) {
return;
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/counter/data/EventDataHandler.java b/kernel/src/main/java/com/itextpdf/kernel/counter/data/EventDataHandler.java
index f690f6d517..d7b0781846 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/counter/data/EventDataHandler.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/counter/data/EventDataHandler.java
@@ -71,6 +71,7 @@ This file is part of the iText (R) project.
* @param data type
*/
public abstract class EventDataHandler> {
+ private final Object createLock = new Object();
private final Object processLock = new Object();
private final IEventDataCache cache;
@@ -97,8 +98,7 @@ public List clear() {
public void register(IEvent event, IMetaInfo metaInfo) {
V data;
- //Synchronization is left here mostly in consistency with cache and process, but factories are usually not thread safe anyway.
- synchronized (factory) {
+ synchronized (createLock) {
data = factory.create(event, metaInfo);
}
if (data != null) {
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/FontUtil.java b/kernel/src/main/java/com/itextpdf/kernel/font/FontUtil.java
index 6275863802..f2c8417a92 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/FontUtil.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/FontUtil.java
@@ -58,6 +58,7 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfStream;
+import java.util.Arrays;
import java.util.HashMap;
import org.slf4j.Logger;
@@ -127,9 +128,7 @@ static String createRandomFontName() {
static int[] convertSimpleWidthsArray(PdfArray widthsArray, int first, int missingWidth) {
int[] res = new int[256];
- for (int i = 0; i < res.length; i++) {
- res[i] = missingWidth;
- }
+ Arrays.fill(res, missingWidth);
if (widthsArray == null) {
Logger logger = LoggerFactory.getLogger(FontUtil.class);
logger.warn(LogMessageConstant.FONT_DICTIONARY_WITH_NO_WIDTHS);
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfFont.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfFont.java
index fbaacb57f1..edce902806 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfFont.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfFont.java
@@ -77,6 +77,8 @@ public abstract class PdfFont extends PdfObjectWrapper {
protected FontProgram fontProgram;
protected static final byte[] EMPTY_BYTES = new byte[0];
+
+ @Deprecated
protected static final double[] DEFAULT_FONT_MATRIX = {0.001, 0, 0, 0.001, 0, 0};
protected Map notdefGlyphs = new HashMap<>();
@@ -208,6 +210,19 @@ public boolean appendDecodedCodesToGlyphsList(List list, PdfString charac
public abstract void writeText(String text, PdfOutputStream stream);
+ /**
+ * Gets the transformation matrix that defines relation between text and glyph spaces.
+ *
+ * @return the font matrix
+ *
+ * @deprecated Use {@link FontProgram#UNITS_NORMALIZATION} constant for conversion between text and glyph space.
+ * For now we opted to always expect that all {@link PdfFont} metrics in glyph-space
+ * are related to text space as 1 to 1000, as it is defined for the majority of fonts. For fonts
+ * which don't necessary follow this rule (see {@link PdfType3Font}), we perform internal normalization
+ * of font metrics in order to adhere to this common expectation.
+ * This method will be removed in next major release.
+ */
+ @Deprecated
public double[] getFontMatrix() {
return DEFAULT_FONT_MATRIX;
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfSimpleFont.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfSimpleFont.java
index 5b2d867446..5fe96906aa 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfSimpleFont.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfSimpleFont.java
@@ -439,17 +439,7 @@ protected void flushFontData(String fontName, PdfName subtype) {
if (isForceWidthsOutput() || !isBuiltInFont() || fontEncoding.hasDifferences()) {
getPdfObject().put(PdfName.FirstChar, new PdfNumber(firstChar));
getPdfObject().put(PdfName.LastChar, new PdfNumber(lastChar));
- PdfArray wd = new PdfArray();
- for (int k = firstChar; k <= lastChar; ++k) {
- if (shortTag[k] == 0) {
- wd.add(new PdfNumber(0));
- } else {
- //prevent lost of widths info
- int uni = fontEncoding.getUnicode(k);
- Glyph glyph = uni > -1 ? getGlyph(uni) : fontProgram.getGlyphByCode(k);
- wd.add(new PdfNumber(getGlyphWidth(glyph)));
- }
- }
+ PdfArray wd = buildWidthsArray(firstChar, lastChar);
getPdfObject().put(PdfName.Widths, wd);
}
PdfDictionary fontDescriptor = !isBuiltInFont() ? getFontDescriptor(fontName) : null;
@@ -514,12 +504,39 @@ protected PdfDictionary getFontDescriptor(String fontName) {
return fontDescriptor;
}
+ protected PdfArray buildWidthsArray(int firstChar, int lastChar) {
+ PdfArray wd = new PdfArray();
+ for (int k = firstChar; k <= lastChar; ++k) {
+ if (shortTag[k] == 0) {
+ wd.add(new PdfNumber(0));
+ } else {
+ int uni = fontEncoding.getUnicode(k);
+ Glyph glyph = uni > -1 ? getGlyph(uni) : fontProgram.getGlyphByCode(k);
+ wd.add(new PdfNumber(glyph != null ? glyph.getWidth() : 0));
+ }
+ }
+ return wd;
+ }
+
protected abstract void addFontStream(PdfDictionary fontDescriptor);
protected void setFontProgram(T fontProgram) {
this.fontProgram = fontProgram;
}
+ /**
+ * Gets glyph width which us ready to be written to the output file.
+ *
+ * @param glyph the glyph which widths is required to be written to the output file
+ *
+ * @return glyph width in glyph-space
+ *
+ * @deprecated This method was introduced to allow overriding of widths array entry writing to
+ * output file. It's now replaced by more specific {@link #buildWidthsArray(int, int)} in order to
+ * avoid confusion between this method and {@link Glyph#getWidth()}.
+ * This method will be removed in the next major release.
+ */
+ @Deprecated
protected double getGlyphWidth(Glyph glyph) {
return glyph != null ? glyph.getWidth() : 0;
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfTrueTypeFont.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfTrueTypeFont.java
index 82b12e0785..262f455b92 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfTrueTypeFont.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfTrueTypeFont.java
@@ -120,11 +120,10 @@ public class PdfTrueTypeFont extends PdfSimpleFont {
public Glyph getGlyph(int unicode) {
if (fontEncoding.canEncode(unicode)) {
Glyph glyph = getFontProgram().getGlyph(fontEncoding.getUnicodeDifference(unicode));
- //TODO TrueType what if font is specific?
if (glyph == null && (glyph = notdefGlyphs.get(unicode)) == null) {
- Glyph notdef = getFontProgram().getGlyphByCode(0);
+ final Glyph notdef = getFontProgram().getGlyphByCode(0);
if (notdef != null) {
- glyph = new Glyph(getFontProgram().getGlyphByCode(0), unicode);
+ glyph = new Glyph(notdef, unicode);
notdefGlyphs.put(unicode, glyph);
}
}
@@ -149,7 +148,6 @@ public void flush() {
return;
}
ensureUnderlyingObjectHasIndirectReference();
- //TODO make subtype class member and simplify this method
if (newFont) {
PdfName subtype;
String fontName;
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java
index f568a35c5c..bd415947b9 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java
@@ -48,6 +48,7 @@ This file is part of the iText (R) project.
import com.itextpdf.io.font.FontEncoding;
import com.itextpdf.io.font.FontMetrics;
import com.itextpdf.io.font.FontNames;
+import com.itextpdf.io.font.FontProgram;
import com.itextpdf.io.font.constants.FontDescriptorFlags;
import com.itextpdf.io.font.constants.FontStretches;
import com.itextpdf.io.font.constants.FontWeights;
@@ -72,26 +73,48 @@ This file is part of the iText (R) project.
* In Type 3 fonts, glyphs are defined by streams of PDF graphics operators.
* These streams are associated with character names. A separate encoding entry
* maps character codes to the appropriate character names for the glyphs.
+ *
+ *
+ * Note, that this class operates in a special way with glyph space units.
+ * In the code when working with fonts, iText expects that 1000 units of glyph-space correspond
+ * to 1 unit of text space. For Type3 fonts this is not always the case and depends on FontMatrix.
+ * That's why in {@link PdfType3Font} the font matrix and all font metrics in glyph space units
+ * are "normalized" in such way, that 1 to 1000 relation is preserved. This is done on
+ * Type3 font initialization, and is reverted back on font flushing, because the actual content
+ * streams of type3 font glyphs are left with original coordinates based on original font matrix.
+ * See also ISO-32000-2, 9.2.4 "Glyph positioning and metrics":
+ *
+ *
+ * "The glyph coordinate system is the space in which an individual character’s glyph is defined. All path
+ * coordinates and metrics shall be interpreted in glyph space. For all font types except Type 3, the units
+ * of glyph space are one-thousandth of a unit of text space; for a Type 3 font, the transformation from
+ * glyph space to text space shall be defined by a font matrix specified in an explicit FontMatrix entry in
+ * the font."
+ *
+ *
+ * Note, that because of this when processing Type3 glyphs content streams either process them completely independent
+ * from this class or take this normalization into account.
+ *
*
- *
* To be able to be wrapped with this {@link PdfObjectWrapper} the {@link PdfObject}
* must be indirect.
*/
public class PdfType3Font extends PdfSimpleFont {
private static final long serialVersionUID = 4940119184993066859L;
+
+ private static final int FONT_BBOX_LLX = 0;
+ private static final int FONT_BBOX_LLY = 1;
+ private static final int FONT_BBOX_URX = 2;
+ private static final int FONT_BBOX_URY = 3;
+
+ @Deprecated
private double[] fontMatrix = DEFAULT_FONT_MATRIX;
/**
- * Used to normalize the values of glyphs widths and bBox measurements.
- * iText process glyph width and bBox width and height in integer values from 0 to 1000.
- * Such behaviour is based on the assumption that this is the most common way to store such values. It also implies
- * that the fontMatrix contains the following values: [0.001, 0, 0, 0.001, 0, 0].
- * However for the other cases of font matrix the values stored inside pdfWidth and bBox arrays need to be normalized
- * by multiplying them by fontMatrix[0] * 1000 to be processed correctly. The opposite procedure, division by
- * dimensionsMultiplier is performed on font flush in order to maintain correct pdfObject for underlysing font.
+ * Used to normalize font metrics expressed in glyph space units. See {@link PdfType3Font}.
*/
- private double dimensionsMultiplier;
+ private double glyphSpaceNormalizationFactor;
/**
* Creates a Type 3 font.
@@ -105,7 +128,7 @@ public class PdfType3Font extends PdfSimpleFont {
embedded = true;
fontProgram = new Type3Font(colorized);
fontEncoding = FontEncoding.createEmptyFontEncoding();
- dimensionsMultiplier = 1.0f;
+ setGlyphSpaceNormalizationFactor(1.0f);
}
/**
@@ -120,7 +143,7 @@ public class PdfType3Font extends PdfSimpleFont {
this(document, colorized);
((Type3Font) fontProgram).setFontName(fontName);
((Type3Font) fontProgram).setFontFamily(fontFamily);
- dimensionsMultiplier = 1.0f;
+ setGlyphSpaceNormalizationFactor(1.0f);
}
/**
@@ -134,22 +157,36 @@ public class PdfType3Font extends PdfSimpleFont {
embedded = true;
fontProgram = new Type3Font(false);
fontEncoding = DocFontEncoding.createDocFontEncoding(fontDictionary.get(PdfName.Encoding), toUnicode);
+
+ double[] fontMatrixArray = readFontMatrix();
+ double[] fontBBoxRect = readFontBBox();
+ double[] widthsArray = readWidths(fontDictionary);
+
+ setGlyphSpaceNormalizationFactor(fontMatrixArray[0] * FontProgram.UNITS_NORMALIZATION);
+
PdfDictionary charProcsDic = fontDictionary.getAsDictionary(PdfName.CharProcs);
PdfDictionary encoding = fontDictionary.getAsDictionary(PdfName.Encoding);
PdfArray differences = encoding != null ? encoding.getAsArray(PdfName.Differences) : null;
if (charProcsDic == null || differences == null) {
LoggerFactory.getLogger(getClass()).warn(LogMessageConstant.TYPE3_FONT_INITIALIZATION_ISSUE);
}
+ fillFontDescriptor(fontDictionary.getAsDictionary(PdfName.FontDescriptor));
- calculateAndSetFontMatrix();
- calculateAndSetBBox();
+ normalize1000UnitsToGlyphSpaceUnits(fontMatrixArray);
+ normalizeGlyphSpaceUnitsTo1000Units(fontBBoxRect);
+ normalizeGlyphSpaceUnitsTo1000Units(widthsArray);
- int firstChar = calculateShortTag(fontDictionary);
- int[] widths = calculateWidth(fontDictionary, firstChar);
+ int firstChar = initializeShortTag(fontDictionary);
+ fontMatrix = fontMatrixArray;
+ initializeFontBBox(fontBBoxRect);
+ initializeTypoAscenderDescender(fontBBoxRect);
+
+ int[] widths = new int[256];
+ for (int i = 0; i < widthsArray.length && firstChar + i < 256; i++) {
+ widths[firstChar + i] = (int) (widthsArray[i]);
+ }
addGlyphsFromDifferences(differences, charProcsDic, widths);
addGlyphsFromCharProcs(charProcsDic, widths);
-
- fillFontDescriptor(fontDictionary.getAsDictionary(PdfName.FontDescriptor));
}
/**
@@ -179,6 +216,15 @@ public void setFontWeight(int fontWeight) {
((Type3Font) fontProgram).setFontWeight(fontWeight);
}
+ /**
+ * Sets cap height.
+ *
+ * @param capHeight integer in glyph-space 1000-units
+ */
+ public void setCapHeight(int capHeight) {
+ ((Type3Font) fontProgram).setCapHeight(capHeight);
+ }
+
/**
* Sets the PostScript italic angle.
*
@@ -235,6 +281,13 @@ public double[] getFontMatrix() {
return this.fontMatrix;
}
+ /**
+ * Sets font matrix, mapping glyph space to text space. Must be identity matrix divided by 1000.
+ * @param fontMatrix an array of six numbers specifying the font matrix,
+ * mapping glyph space to text space.
+ * @deprecated will be made internal in next major release
+ */
+ @Deprecated
public void setFontMatrix(double[] fontMatrix) {
this.fontMatrix = fontMatrix;
}
@@ -326,7 +379,9 @@ protected PdfDictionary getFontDescriptor(String fontName) {
fontDescriptor.put(PdfName.Type, PdfName.FontDescriptor);
FontMetrics fontMetrics = fontProgram.getFontMetrics();
- fontDescriptor.put(PdfName.CapHeight, new PdfNumber(fontMetrics.getCapHeight()));
+
+ int capHeight = fontMetrics.getCapHeight();
+ fontDescriptor.put(PdfName.CapHeight, new PdfNumber(normalize1000UnitsToGlyphSpaceUnits(capHeight)));
fontDescriptor.put(PdfName.ItalicAngle, new PdfNumber(fontMetrics.getItalicAngle()));
FontNames fontNames = fontProgram.getFontNames();
@@ -353,6 +408,23 @@ && getPdfObject().getIndirectReference().getDocument().isTagged()) {
return null;
}
+ @Override
+ protected PdfArray buildWidthsArray(int firstChar, int lastChar) {
+ double[] widths = new double[lastChar - firstChar + 1];
+ for (int k = firstChar; k <= lastChar; ++k) {
+ int i = k - firstChar;
+ if (shortTag[k] == 0) {
+ widths[i] = 0;
+ } else {
+ int uni = getFontEncoding().getUnicode(k);
+ Glyph glyph = uni > -1 ? getGlyph(uni) : getFontProgram().getGlyphByCode(k);
+ widths[i] = glyph != null ? glyph.getWidth() : 0;
+ }
+ }
+ normalize1000UnitsToGlyphSpaceUnits(widths);
+ return new PdfArray(widths);
+ }
+
@Override
protected void addFontStream(PdfDictionary fontDescriptor) {
}
@@ -363,19 +435,15 @@ protected PdfDocument getDocument() {
@Override
protected double getGlyphWidth(Glyph glyph) {
- return glyph != null ? glyph.getWidth()/this.getDimensionsMultiplier() : 0;
+ return glyph != null ? glyph.getWidth() / this.getGlyphSpaceNormalizationFactor() : 0;
}
- /**
- * Gets dimensionsMultiplier for normalizing glyph width, fontMatrix values and bBox dimensions.
- * @return dimensionsMultiplier double value
- */
- double getDimensionsMultiplier() {
- return dimensionsMultiplier;
+ final double getGlyphSpaceNormalizationFactor() {
+ return glyphSpaceNormalizationFactor;
}
- void setDimensionsMultiplier(double dimensionsMultiplier) {
- this.dimensionsMultiplier = dimensionsMultiplier;
+ final void setGlyphSpaceNormalizationFactor(double glyphSpaceNormalizationFactor) {
+ this.glyphSpaceNormalizationFactor = glyphSpaceNormalizationFactor;
}
private void addGlyphsFromDifferences(PdfArray differences, PdfDictionary charProcsDic, int[] widths) {
@@ -460,11 +528,18 @@ private void flushFontData() {
}
}
getPdfObject().put(PdfName.CharProcs, charProcs);
- for (int i = 0; i < fontMatrix.length; i++) {
- fontMatrix[i] *= getDimensionsMultiplier();
- }
- getPdfObject().put(PdfName.FontMatrix, new PdfArray(getFontMatrix()));
- getPdfObject().put(PdfName.FontBBox, normalizeBBox(fontProgram.getFontMetrics().getBbox()));
+
+ double[] fontMatrixDouble = getFontMatrix();
+ int[] fontBBoxInt = getFontProgram().getFontMetrics().getBbox();
+ double[] fontBBoxDouble = new double[] {
+ fontBBoxInt[FONT_BBOX_LLX], fontBBoxInt[FONT_BBOX_LLY],
+ fontBBoxInt[FONT_BBOX_URX], fontBBoxInt[FONT_BBOX_URY]};
+
+ normalizeGlyphSpaceUnitsTo1000Units(fontMatrixDouble);
+ normalize1000UnitsToGlyphSpaceUnits(fontBBoxDouble);
+
+ getPdfObject().put(PdfName.FontMatrix, new PdfArray(fontMatrixDouble));
+ getPdfObject().put(PdfName.FontBBox, new PdfArray(fontBBoxDouble));
String fontName = fontProgram.getFontNames().getFontName();
super.flushFontData(fontName, PdfName.Type3);
makeObjectIndirect(getPdfObject().get(PdfName.Widths));
@@ -472,22 +547,22 @@ private void flushFontData() {
getPdfObject().remove(PdfName.BaseFont);
}
- private int[] calculateWidth(PdfDictionary fontDictionary, int firstChar) {
+ private double[] readWidths(PdfDictionary fontDictionary) {
PdfArray pdfWidths = fontDictionary.getAsArray(PdfName.Widths);
if (pdfWidths == null) {
throw new PdfException(PdfException.MissingRequiredFieldInFontDictionary).setMessageParams(PdfName.Widths);
}
- double[] multipliedWidths = new double[pdfWidths.size()];
+ double[] widths = new double[pdfWidths.size()];
for (int i = 0; i < pdfWidths.size(); i++) {
- multipliedWidths[i] = pdfWidths.getAsNumber(i).doubleValue() * getDimensionsMultiplier();
+ PdfNumber n = pdfWidths.getAsNumber(i);
+ widths[i] = n != null ? n.doubleValue() : 0;
}
- PdfArray multipliedPdfWidths = new PdfArray(multipliedWidths);
- return FontUtil.convertSimpleWidthsArray(multipliedPdfWidths, firstChar, 0);
+ return widths;
}
- private int calculateShortTag(PdfDictionary fontDictionary) {
+ private int initializeShortTag(PdfDictionary fontDictionary) {
int firstChar = normalizeFirstLastChar(fontDictionary.getAsNumber(PdfName.FirstChar), 0);
int lastChar = normalizeFirstLastChar(fontDictionary.getAsNumber(PdfName.LastChar),
PdfFont.SIMPLE_FONT_MAX_CHAR_CODE_VALUE);
@@ -497,19 +572,21 @@ private int calculateShortTag(PdfDictionary fontDictionary) {
return firstChar;
}
- private void calculateAndSetBBox() {
- if (getPdfObject().containsKey(PdfName.FontBBox)) {
- PdfArray fontBBox = getPdfObject().getAsArray(PdfName.FontBBox);
- fontProgram.getFontMetrics().setBbox((int)(fontBBox.getAsNumber(0).doubleValue() * getDimensionsMultiplier()),
- (int)(fontBBox.getAsNumber(1).doubleValue() * getDimensionsMultiplier()),
- (int)(fontBBox.getAsNumber(2).doubleValue() * getDimensionsMultiplier()),
- (int)(fontBBox.getAsNumber(3).doubleValue() * getDimensionsMultiplier()));
- } else {
- fontProgram.getFontMetrics().setBbox(0, 0, 0, 0);
+ private double[] readFontBBox() {
+ PdfArray fontBBox = getPdfObject().getAsArray(PdfName.FontBBox);
+ if (fontBBox != null) {
+ double llx = fontBBox.getAsNumber(FONT_BBOX_LLX).doubleValue();
+ double lly = fontBBox.getAsNumber(FONT_BBOX_LLY).doubleValue();
+ double urx = fontBBox.getAsNumber(FONT_BBOX_URX).doubleValue();
+ double ury = fontBBox.getAsNumber(FONT_BBOX_URY).doubleValue();
+
+ return new double[] {llx, lly, urx, ury};
}
+
+ return new double[] {0, 0, 0, 0};
}
- private void calculateAndSetFontMatrix() {
+ private double[] readFontMatrix() {
PdfArray fontMatrixArray = getPdfObject().getAsArray(PdfName.FontMatrix);
if (fontMatrixArray == null) {
throw new PdfException(PdfException.MissingRequiredFieldInFontDictionary)
@@ -519,18 +596,55 @@ private void calculateAndSetFontMatrix() {
for (int i = 0; i < fontMatrixArray.size(); i++) {
fontMatrix[i] = ((PdfNumber) fontMatrixArray.get(i)).getValue();
}
- setDimensionsMultiplier(fontMatrix[0] * 1000);
- for (int i = 0; i < 6; i++) {
- fontMatrix[i] /= getDimensionsMultiplier();
+ return fontMatrix;
+ }
+
+ private void initializeTypoAscenderDescender(double[] fontBBoxRect) {
+ // iText uses typo ascender/descender for text extraction, that's why we need to set
+ // them here to values relative to actual glyph metrics values.
+ ((Type3Font) fontProgram).setTypoAscender((int) fontBBoxRect[FONT_BBOX_URY]);
+ ((Type3Font) fontProgram).setTypoDescender((int) fontBBoxRect[FONT_BBOX_LLY]);
+ }
+
+ private void initializeFontBBox(double[] fontBBoxRect) {
+ fontProgram.getFontMetrics().setBbox(
+ (int) fontBBoxRect[FONT_BBOX_LLX],
+ (int) fontBBoxRect[FONT_BBOX_LLY],
+ (int) fontBBoxRect[FONT_BBOX_URX],
+ (int) fontBBoxRect[FONT_BBOX_URY]
+ );
+ }
+
+ private void normalizeGlyphSpaceUnitsTo1000Units(double[] array) {
+ for (int i = 0; i < array.length; i++) {
+ array[i] = normalizeGlyphSpaceUnitsTo1000Units(array[i]);;
+ }
+ }
+
+ private double normalizeGlyphSpaceUnitsTo1000Units(double value) {
+ return value * getGlyphSpaceNormalizationFactor();
+ }
+
+ private void normalize1000UnitsToGlyphSpaceUnits(double[] array) {
+ for (int i = 0; i < array.length; i++) {
+ array[i] = normalize1000UnitsToGlyphSpaceUnits(array[i]);
}
- setFontMatrix(fontMatrix);
+ }
+
+ private double normalize1000UnitsToGlyphSpaceUnits(double value) {
+ return value / getGlyphSpaceNormalizationFactor();
}
private void fillFontDescriptor(PdfDictionary fontDesc) {
if (fontDesc == null) {
return;
}
- PdfNumber v = fontDesc.getAsNumber(PdfName.ItalicAngle);
+ PdfNumber v = fontDesc.getAsNumber(PdfName.CapHeight);
+ if (v != null) {
+ double capHeight = v.doubleValue();
+ setCapHeight((int) normalizeGlyphSpaceUnitsTo1000Units(capHeight));
+ }
+ v = fontDesc.getAsNumber(PdfName.ItalicAngle);
if (v != null) {
setItalicAngle(v.intValue());
}
@@ -560,12 +674,4 @@ private int normalizeFirstLastChar(PdfNumber firstLast, int defaultValue) {
int result = firstLast.intValue();
return result < 0 || result > PdfFont.SIMPLE_FONT_MAX_CHAR_CODE_VALUE ? defaultValue : result;
}
-
- private PdfArray normalizeBBox(int[] bBox) {
- double [] normalizedBBox = new double [4];
- for (int i = 0; i < 4; i++) {
- normalizedBBox[i] = bBox[i] / getDimensionsMultiplier();
- }
- return new PdfArray(normalizedBBox);
- }
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/font/Type3Font.java b/kernel/src/main/java/com/itextpdf/kernel/font/Type3Font.java
index 7b4a938dd7..9895f55a5a 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/font/Type3Font.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/font/Type3Font.java
@@ -147,7 +147,7 @@ public int getNumberOfGlyphs() {
*/
@Override
protected void setFontName(String fontName) {
- //This dummy override allows PdfType3Font to set font name because of different modules.
+ // This dummy override allows PdfType3Font to use setter from different module.
super.setFontName(fontName);
}
@@ -158,7 +158,7 @@ protected void setFontName(String fontName) {
*/
@Override
protected void setFontFamily(String fontFamily) {
- //This dummy override allows PdfType3Font to set font name because of different modules.
+ // This dummy override allows PdfType3Font to use setter from different module.
super.setFontFamily(fontFamily);
}
@@ -169,7 +169,7 @@ protected void setFontFamily(String fontFamily) {
*/
@Override
protected void setFontWeight(int fontWeight) {
- //This dummy override allows PdfType3Font to set font name because of different modules.
+ // This dummy override allows PdfType3Font to use setter from different module.
super.setFontWeight(fontWeight);
}
@@ -180,23 +180,46 @@ protected void setFontWeight(int fontWeight) {
*/
@Override
protected void setFontStretch(String fontWidth) {
- //This dummy override allows PdfType3Font to set font name because of different modules.
+ // This dummy override allows PdfType3Font to use setter from different module.
super.setFontStretch(fontWidth);
}
/**
- * Sets the PostScript italic angel.
- *
- * Italic angle in counter-clockwise degrees from the vertical. Zero for upright text, negative for text that leans to the right (forward).
- *
- * @param italicAngle in counter-clockwise degrees from the vertical
+ * {@inheritDoc}
*/
- @Override //This dummy override allows PdfType3Font to set the PostScript italicAngel because of different modules.
+ @Override
+ protected void setCapHeight(int capHeight) {
+ // This dummy override allows PdfType3Font to use setter from different module.
+ super.setCapHeight(capHeight);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
protected void setItalicAngle(int italicAngle) {
- //This dummy override allows PdfType3Font to set font name because of different modules.
+ // This dummy override allows PdfType3Font to use setter from different module.
super.setItalicAngle(italicAngle);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setTypoAscender(int ascender) {
+ // This dummy override allows PdfType3Font to use setter from different module.
+ super.setTypoAscender(ascender);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setTypoDescender(int descender) {
+ // This dummy override allows PdfType3Font to use setter from different module.
+ super.setTypoDescender(descender);
+ }
+
/**
* Sets Font descriptor flags.
* @see FontDescriptorFlags
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandler.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandler.java
new file mode 100644
index 0000000000..95f2ac8203
--- /dev/null
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandler.java
@@ -0,0 +1,83 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.kernel.pdf;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+class EncryptedEmbeddedStreamsHandler implements Serializable {
+
+ private static final long serialVersionUID = -4542644924377740467L;
+
+ private final PdfDocument document;
+
+ private final Set embeddedStreams = new HashSet<>();
+
+ /**
+ * Creates {@link EncryptedEmbeddedStreamsHandler} instance.
+ *
+ * @param document {@link PdfDocument} associated with this handler
+ */
+ EncryptedEmbeddedStreamsHandler(PdfDocument document) {
+ this.document = document;
+ }
+
+ /**
+ * Stores all embedded streams present in the {@link PdfDocument}.
+ * Note that during this method we traverse through every indirect object of the document.
+ */
+ void storeAllEmbeddedStreams() {
+ for (int i = 0; i < document.getNumberOfPdfObjects(); ++i) {
+ PdfObject indirectObject = document.getPdfObject(i);
+ if (indirectObject instanceof PdfDictionary) {
+ PdfStream embeddedStream = getEmbeddedFileStreamFromDictionary((PdfDictionary) indirectObject);
+ if (embeddedStream != null) {
+ storeEmbeddedStream(embeddedStream);
+ }
+ }
+ }
+ }
+
+ void storeEmbeddedStream(PdfStream embeddedStream) {
+ embeddedStreams.add(embeddedStream);
+ }
+
+ /**
+ * Checks, whether this {@link PdfStream} was stored as embedded stream.
+ *
+ * @param stream to be checked
+ * @return true if this stream is embedded, false otherwise
+ */
+ boolean isStreamStoredAsEmbedded(PdfStream stream) {
+ return embeddedStreams.contains(stream);
+ }
+
+ private static PdfStream getEmbeddedFileStreamFromDictionary(PdfDictionary dictionary) {
+ PdfDictionary embeddedFileDictionary = dictionary.getAsDictionary(PdfName.EF);
+ if (PdfName.Filespec.equals(dictionary.getAsName(PdfName.Type)) && embeddedFileDictionary != null) {
+ return embeddedFileDictionary.getAsStream(PdfName.F);
+ }
+ return null;
+ }
+}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfAConformanceLevel.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfAConformanceLevel.java
index d6ae15136c..1ea00a114e 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfAConformanceLevel.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfAConformanceLevel.java
@@ -120,7 +120,7 @@ public static PdfAConformanceLevel getConformanceLevel(XMPMeta meta) {
try {
conformanceXmpProperty = meta.getProperty(XMPConst.NS_PDFA_ID, XMPConst.CONFORMANCE);
partXmpProperty = meta.getProperty(XMPConst.NS_PDFA_ID, XMPConst.PART);
- } catch (XMPException exc) {
+ } catch (XMPException ignored) {
}
if (conformanceXmpProperty == null || partXmpProperty == null) {
return null;
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java
index 1300aa9dbd..9cb1212602 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java
@@ -44,6 +44,7 @@ This file is part of the iText (R) project.
package com.itextpdf.kernel.pdf;
import com.itextpdf.io.LogMessageConstant;
+import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.source.ByteArrayOutputStream;
import com.itextpdf.io.source.ByteUtils;
import com.itextpdf.io.source.RandomAccessFileOrArray;
@@ -229,6 +230,8 @@ public class PdfDocument implements IEventDispatcher, Closeable, Serializable {
*/
MemoryLimitsAwareHandler memoryLimitsAwareHandler = null;
+ private EncryptedEmbeddedStreamsHandler encryptedEmbeddedStreamsHandler;
+
/**
* Open PDF document in reading mode.
*
@@ -459,6 +462,17 @@ public PdfPage getLastPage() {
return getPage(getNumberOfPages());
}
+ /**
+ * Marks {@link PdfStream} object as embedded file stream. Note that this method is for internal usage.
+ * To add an embedded file to the PDF document please use specialized API for file attachments.
+ * (e.g. {@link PdfDocument#addFileAttachment(String, PdfFileSpec)}, {@link PdfPage#addAnnotation(PdfAnnotation)})
+ *
+ * @param stream to be marked as embedded file stream
+ */
+ public void markStreamAsEmbeddedFile(PdfStream stream) {
+ encryptedEmbeddedStreamsHandler.storeEmbeddedStream(stream);
+ }
+
/**
* Creates and adds new page to the end of document.
*
@@ -664,11 +678,18 @@ public void removePage(int pageNum) {
/**
* Gets document information dictionary.
+ * {@link PdfDocument#info} is lazy initialized. It will be initialized during the first call of this method.
*
* @return document information dictionary.
*/
public PdfDocumentInfo getDocumentInfo() {
checkClosingStatus();
+ if (info == null) {
+ PdfObject infoDict = trailer.get(PdfName.Info);
+ info = new PdfDocumentInfo(
+ infoDict instanceof PdfDictionary ? (PdfDictionary) infoDict : new PdfDictionary(), this);
+ XmpMetaInfoConverter.appendMetadataToInfo(xmpMetadata, info);
+ }
return info;
}
@@ -839,7 +860,7 @@ public void close() {
// In PDF 2.0, all the values except CreationDate and ModDate are deprecated. Remove them now
if (pdfVersion.compareTo(PdfVersion.PDF_2_0) >= 0) {
for (PdfName deprecatedKey : PdfDocumentInfo.PDF20_DEPRECATED_KEYS) {
- info.getPdfObject().remove(deprecatedKey);
+ getDocumentInfo().getPdfObject().remove(deprecatedKey);
}
}
if (getXmpMetadata() != null) {
@@ -892,8 +913,8 @@ public void close() {
}
- if (info.getPdfObject().isModified()) {
- info.getPdfObject().flush(false);
+ if (getDocumentInfo().getPdfObject().isModified()) {
+ getDocumentInfo().getPdfObject().flush(false);
}
flushFonts();
@@ -941,7 +962,7 @@ public void close() {
tryFlushTagStructure(false);
}
catalog.getPdfObject().flush(false);
- info.getPdfObject().flush(false);
+ getDocumentInfo().getPdfObject().flush(false);
flushFonts();
if (writer.crypto != null) {
@@ -977,7 +998,7 @@ public void close() {
// entries existing in the trailer object and corresponding fields. This inconsistency
// may appear when user gets trailer and explicitly sets new root or info dictionaries.
trailer.put(PdfName.Root, catalog.getPdfObject());
- trailer.put(PdfName.Info, info.getPdfObject());
+ trailer.put(PdfName.Info, getDocumentInfo().getPdfObject());
//By this time original and modified document ids should always be not null due to initializing in
@@ -1056,7 +1077,8 @@ public PdfDocument setTagged() {
/**
* Gets {@link PdfStructTreeRoot} of tagged document.
*
- * @return {@link PdfStructTreeRoot} in case tagged document, otherwise false.
+ * @return {@link PdfStructTreeRoot} in case document is tagged, otherwise it returns null.
+ *
* @see #isTagged()
* @see #getNextStructParentIndex()
*/
@@ -1068,6 +1090,7 @@ public PdfStructTreeRoot getStructTreeRoot() {
* Gets next parent index of tagged document.
*
* @return -1 if document is not tagged, or >= 0 if tagged.
+ *
* @see #isTagged()
* @see #getNextStructParentIndex()
*/
@@ -1905,9 +1928,11 @@ protected void flushObject(PdfObject pdfObject, boolean canBeInObjStm) throws IO
*/
protected void open(PdfVersion newPdfVersion) {
this.fingerPrint = new FingerPrint();
+ this.encryptedEmbeddedStreamsHandler = new EncryptedEmbeddedStreamsHandler(this);
try {
EventCounterHandler.getInstance().onEvent(CoreEvent.PROCESS, properties.metaInfo, getClass());
+ boolean embeddedStreamsSavedOnReading = false;
if (reader != null) {
if (reader.pdfDocument != null) {
throw new PdfException(PdfException.PdfReaderHasBeenAlreadyUtilized);
@@ -1918,6 +1943,10 @@ protected void open(PdfVersion newPdfVersion) {
memoryLimitsAwareHandler = new MemoryLimitsAwareHandler(reader.tokens.getSafeFile().length());
}
reader.readPdf();
+ if (reader.decrypt != null && reader.decrypt.isEmbeddedFilesOnly()) {
+ encryptedEmbeddedStreamsHandler.storeAllEmbeddedStreams();
+ embeddedStreamsSavedOnReading = true;
+ }
for (ICounter counter : getCounters()) {
counter.onDocumentRead(reader.getFileLength());
}
@@ -1931,14 +1960,13 @@ protected void open(PdfVersion newPdfVersion) {
PdfStream xmpMetadataStream = catalog.getPdfObject().getAsStream(PdfName.Metadata);
if (xmpMetadataStream != null) {
xmpMetadata = xmpMetadataStream.getBytes();
- try {
- reader.pdfAConformanceLevel = PdfAConformanceLevel.getConformanceLevel(XMPMetaFactory.parseFromBuffer(xmpMetadata));
- } catch (XMPException ignored) {
+ if (!this.getClass().equals(PdfDocument.class)) {
+ // TODO DEVSIX-5292 If somebody extends PdfDocument we have to initialize document info
+ // and conformance level to provide compatibility. This code block shall be removed
+ reader.getPdfAConformanceLevel();
+ getDocumentInfo();
}
}
- PdfObject infoDict = trailer.get(PdfName.Info);
- info = new PdfDocumentInfo(infoDict instanceof PdfDictionary ? (PdfDictionary) infoDict : new PdfDictionary(), this);
- XmpMetaInfoConverter.appendMetadataToInfo(xmpMetadata, info);
PdfDictionary str = catalog.getPdfObject().getAsDictionary(PdfName.StructTreeRoot);
if (str != null) {
@@ -1964,10 +1992,10 @@ protected void open(PdfVersion newPdfVersion) {
info = new PdfDocumentInfo(this).addCreationDate();
}
updateProducerInInfoDictionary();
- info.addModDate();
+ getDocumentInfo().addModDate();
trailer = new PdfDictionary();
trailer.put(PdfName.Root, catalog.getPdfObject().getIndirectReference());
- trailer.put(PdfName.Info, info.getPdfObject().getIndirectReference());
+ trailer.put(PdfName.Info, getDocumentInfo().getPdfObject().getIndirectReference());
if (reader != null) {
// If the reader's trailer contains an ID entry, let's copy it over to the new trailer
@@ -2046,6 +2074,9 @@ protected void open(PdfVersion newPdfVersion) {
writer.initCryptoIfSpecified(pdfVersion);
}
if (writer.crypto != null) {
+ if (!embeddedStreamsSavedOnReading && writer.crypto.isEmbeddedFilesOnly()) {
+ encryptedEmbeddedStreamsHandler.storeAllEmbeddedStreams();
+ }
if (writer.crypto.getCryptoMode() < EncryptionConstants.ENCRYPTION_AES_256) {
VersionConforming.validatePdfVersionForDeprecatedFeatureLogWarn(this, PdfVersion.PDF_2_0, VersionConforming.DEPRECATED_ENCRYPTION_ALGORITHMS);
} else if (writer.crypto.getCryptoMode() == EncryptionConstants.ENCRYPTION_AES_256) {
@@ -2093,7 +2124,7 @@ protected void updateXmpMetadata() {
*/
protected XMPMeta updateDefaultXmpMetadata() throws XMPException {
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(getXmpMetadata(true));
- XmpMetaInfoConverter.appendDocumentInfoToMetadata(info, xmpMeta);
+ XmpMetaInfoConverter.appendDocumentInfoToMetadata(getDocumentInfo(), xmpMeta);
if (isTagged() && writer.properties.addUAXmpMetadata && !isXmpMetaHasProperty(xmpMeta, XMPConst.NS_PDFUA_ID, XMPConst.PART)) {
xmpMeta.setPropertyInteger(XMPConst.NS_PDFUA_ID, XMPConst.PART, 1, new PropertyOptions(PropertyOptions.SEPARATE_NODE));
@@ -2188,6 +2219,10 @@ long getDocumentId() {
return documentId;
}
+ boolean doesStreamBelongToEmbeddedFile(PdfStream stream) {
+ return encryptedEmbeddedStreamsHandler.isStreamStoredAsEmbedded(stream);
+ }
+
/**
* Gets iText version info.
*
@@ -2203,16 +2238,18 @@ boolean hasAcroForm() {
private void updateProducerInInfoDictionary() {
String producer = null;
+ PdfDictionary documentInfoObject = getDocumentInfo().getPdfObject();
if (reader == null) {
producer = versionInfo.getVersion();
} else {
- if (info.getPdfObject().containsKey(PdfName.Producer)) {
- final PdfString producerPdfStr = info.getPdfObject().getAsString(PdfName.Producer);
+ if (documentInfoObject.containsKey(PdfName.Producer)) {
+ final PdfString producerPdfStr = documentInfoObject.getAsString(PdfName.Producer);
producer = producerPdfStr == null ? null : producerPdfStr.toUnicodeString();
}
producer = addModifiedPostfix(producer);
}
- info.getPdfObject().put(PdfName.Producer, new PdfString(producer));
+
+ documentInfoObject.put(PdfName.Producer, new PdfString(producer, PdfEncodings.UNICODE_BIG));
}
/**
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryption.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryption.java
index cb03f594ca..d6421c2787 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryption.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryption.java
@@ -484,7 +484,6 @@ private int setCryptoMode(int mode, int length) {
revision = STANDARD_ENCRYPTION_40;
break;
case EncryptionConstants.STANDARD_ENCRYPTION_128:
- embeddedFilesOnly = false;
if (length > 0) {
setKeyLength(length);
} else {
@@ -514,6 +513,7 @@ private int readAndSetCryptoModeForStdHandler(PdfDictionary encDict) {
if (rValue == null)
throw new PdfException(PdfException.IllegalRValue);
int revision = rValue.intValue();
+ boolean embeddedFilesOnlyMode = readEmbeddedFilesOnlyFromEncryptDictionary(encDict);
switch (revision) {
case 2:
cryptoMode = EncryptionConstants.STANDARD_ENCRYPTION_40;
@@ -545,6 +545,9 @@ private int readAndSetCryptoModeForStdHandler(PdfDictionary encDict) {
if (em != null && !em.getValue()) {
cryptoMode |= EncryptionConstants.DO_NOT_ENCRYPT_METADATA;
}
+ if (embeddedFilesOnlyMode) {
+ cryptoMode |= EncryptionConstants.EMBEDDED_FILES_ONLY;
+ }
break;
case 5:
case 6:
@@ -553,6 +556,9 @@ private int readAndSetCryptoModeForStdHandler(PdfDictionary encDict) {
if (em5 != null && !em5.getValue()) {
cryptoMode |= EncryptionConstants.DO_NOT_ENCRYPT_METADATA;
}
+ if (embeddedFilesOnlyMode) {
+ cryptoMode |= EncryptionConstants.EMBEDDED_FILES_ONLY;
+ }
break;
default:
throw new PdfException(PdfException.UnknownEncryptionTypeREq1).setMessageParams(rValue);
@@ -570,6 +576,7 @@ private int readAndSetCryptoModeForPubSecHandler(PdfDictionary encDict) {
if (vValue == null)
throw new PdfException(PdfException.IllegalVValue);
int v = vValue.intValue();
+ boolean embeddedFilesOnlyMode = readEmbeddedFilesOnlyFromEncryptDictionary(encDict);
switch (v) {
case 1:
cryptoMode = EncryptionConstants.STANDARD_ENCRYPTION_40;
@@ -608,6 +615,9 @@ private int readAndSetCryptoModeForPubSecHandler(PdfDictionary encDict) {
if (em != null && !em.getValue()) {
cryptoMode |= EncryptionConstants.DO_NOT_ENCRYPT_METADATA;
}
+ if (embeddedFilesOnlyMode) {
+ cryptoMode |= EncryptionConstants.EMBEDDED_FILES_ONLY;
+ }
break;
default:
throw new PdfException(PdfException.UnknownEncryptionTypeVEq1, vValue);
@@ -615,6 +625,23 @@ private int readAndSetCryptoModeForPubSecHandler(PdfDictionary encDict) {
return setCryptoMode(cryptoMode, length);
}
+ static boolean readEmbeddedFilesOnlyFromEncryptDictionary(PdfDictionary encDict) {
+ PdfName embeddedFilesFilter = encDict.getAsName(PdfName.EFF);
+ boolean encryptEmbeddedFiles = !PdfName.Identity.equals(embeddedFilesFilter) && embeddedFilesFilter != null;
+ boolean encryptStreams = !PdfName.Identity.equals(encDict.getAsName(PdfName.StmF));
+ boolean encryptStrings = !PdfName.Identity.equals(encDict.getAsName(PdfName.StrF));
+ if (encryptStreams || encryptStrings || !encryptEmbeddedFiles) {
+ return false;
+ }
+
+ PdfDictionary cfDictionary = encDict.getAsDictionary(PdfName.CF);
+ if (cfDictionary != null) {
+ // Here we check if the crypt filter for embedded files and the filter in the CF dictionary are the same
+ return cfDictionary.getAsDictionary(embeddedFilesFilter) != null;
+ }
+ return false;
+ }
+
private int fixAccessibilityPermissionPdf20(int permissions) {
// This bit was previously used to determine whether
// content could be extracted for the purposes of accessibility,
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryptor.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryptor.java
index 4c12e6d0f7..5b25587319 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryptor.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfEncryptor.java
@@ -43,6 +43,7 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.kernel.pdf;
+import java.io.IOException;
import java.io.OutputStream;
import java.security.PrivateKey;
import java.util.Map;
@@ -241,12 +242,15 @@ public PdfEncryptor setEncryptionProperties(EncryptionProperties properties) {
public void encrypt(PdfReader reader, OutputStream os, Map newInfo) {
WriterProperties writerProperties = new WriterProperties();
writerProperties.encryptionProperties = properties;
- PdfWriter writer = new PdfWriter(os, writerProperties);
StampingProperties stampingProperties = new StampingProperties();
stampingProperties.setEventCountingMetaInfo(metaInfo);
- PdfDocument document = new PdfDocument(reader, writer, stampingProperties);
- document.getDocumentInfo().setMoreInfo(newInfo);
- document.close();
+ try (PdfWriter writer = new PdfWriter(os, writerProperties);
+ PdfDocument document = new PdfDocument(reader, writer, stampingProperties)) {
+ document.getDocumentInfo().setMoreInfo(newInfo);
+ } catch (IOException e) {
+ //The close() method of OutputStream throws an exception, but we don't need to do anything in this case,
+ // because OutputStream#close() does nothing.
+ }
}
/**
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutputStream.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutputStream.java
index f972f6a5e7..5d2337d3b7 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutputStream.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfOutputStream.java
@@ -298,7 +298,8 @@ private void write(PdfStream pdfStream) {
java.io.OutputStream fout = this;
DeflaterOutputStream def = null;
OutputStreamEncryption ose = null;
- if (crypto != null && !crypto.isEmbeddedFilesOnly()) {
+ if (crypto != null &&
+ (!crypto.isEmbeddedFilesOnly() || document.doesStreamBelongToEmbeddedFile(pdfStream))) {
fout = ose = crypto.getEncryptionStream(fout);
}
if (toCompress && (allowCompression || userDefinedCompression)) {
@@ -390,7 +391,7 @@ private void write(PdfStream pdfStream) {
}
protected boolean checkEncryption(PdfStream pdfStream) {
- if (crypto == null || crypto.isEmbeddedFilesOnly()) {
+ if (crypto == null || (crypto.isEmbeddedFilesOnly() && !document.doesStreamBelongToEmbeddedFile(pdfStream))) {
return false;
} else if (isXRefStream(pdfStream)) {
// The cross-reference stream shall not be encrypted
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java
index a9c2393554..85aa1f65db 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java
@@ -64,6 +64,9 @@ This file is part of the iText (R) project.
import java.io.InputStream;
import java.io.Serializable;
import java.util.Map;
+
+import com.itextpdf.kernel.xmp.XMPException;
+import com.itextpdf.kernel.xmp.XMPMetaFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -387,7 +390,8 @@ public byte[] readStreamBytesRaw(PdfStream stream) throws IOException {
file.seek(stream.getOffset());
bytes = new byte[length];
file.readFully(bytes);
- if (decrypt != null && !decrypt.isEmbeddedFilesOnly()) {
+ boolean embeddedStream = pdfDocument.doesStreamBelongToEmbeddedFile(stream);
+ if (decrypt != null && (!decrypt.isEmbeddedFilesOnly() || embeddedStream)) {
PdfObject filter = stream.get(PdfName.Filter, true);
boolean skip = false;
if (filter != null) {
@@ -605,13 +609,24 @@ public int getCryptoMode() {
}
/**
- * Gets the declared Pdf/A conformance level of the source document that is being read.
+ * Gets the declared PDF/A conformance level of the source document that is being read.
* Note that this information is provided via XMP metadata and is not verified by iText.
+ * {@link PdfReader#pdfAConformanceLevel} is lazy initialized.
+ * It will be initialized during the first call of this method.
*
- * @return conformance level of the source document, or {@code null} if no Pdf/A
+ * @return conformance level of the source document, or {@code null} if no PDF/A
* conformance level information is specified.
*/
public PdfAConformanceLevel getPdfAConformanceLevel() {
+ if (pdfAConformanceLevel == null) {
+ if (pdfDocument != null && pdfDocument.getXmpMetadata() != null) {
+ try {
+ pdfAConformanceLevel = PdfAConformanceLevel.getConformanceLevel(
+ XMPMetaFactory.parseFromBuffer(pdfDocument.getXmpMetadata()));
+ } catch (XMPException ignored) {
+ }
+ }
+ }
return pdfAConformanceLevel;
}
@@ -1297,8 +1312,19 @@ private void readDecryptObj() {
* @throws IOException if there is a problem reading the byte source
*/
private static PdfTokenizer getOffsetTokeniser(IRandomAccessSource byteSource) throws IOException {
+ com.itextpdf.io.IOException possibleException = null;
PdfTokenizer tok = new PdfTokenizer(new RandomAccessFileOrArray(byteSource));
- int offset = tok.getHeaderOffset();
+ int offset;
+ try {
+ offset = tok.getHeaderOffset();
+ } catch (com.itextpdf.io.IOException ex) {
+ possibleException = ex;
+ throw possibleException;
+ } finally {
+ if (possibleException != null) {
+ tok.close();
+ }
+ }
if (offset != 0) {
IRandomAccessSource offsetSource = new WindowRandomAccessSource(byteSource, offset);
tok = new PdfTokenizer(new RandomAccessFileOrArray(offsetSource));
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/action/PdfAction.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/action/PdfAction.java
index eb54361233..c1ae813148 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/action/PdfAction.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/action/PdfAction.java
@@ -709,6 +709,12 @@ private static void validateRemoteDestination(PdfDestination destination) {
}
}
+ /**
+ * Validates not remote destination against the PDF specification and in case of invalidity logs a warning.
+ * See section 12.3.2.2 of ISO 32000-1.
+ *
+ * @param destination the {@link PdfDestination destination} to be validated
+ */
public static void validateNotRemoteDestination(PdfDestination destination) {
if (destination instanceof PdfExplicitRemoteGoToDestination) {
LoggerFactory.getLogger(PdfAction.class).warn(LogMessageConstant.INVALID_DESTINATION_TYPE);
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/Pdf3DAnnotation.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/Pdf3DAnnotation.java
index a4312881af..aee7f7ae68 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/Pdf3DAnnotation.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/Pdf3DAnnotation.java
@@ -50,53 +50,139 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfObject;
-
+/**
+ * This class represents 3D annotations by which 3D artwork shall be represented in a PDF document.
+ * See also ISO-32000-2 13.6.2 "3D annotations".
+ */
public class Pdf3DAnnotation extends PdfAnnotation {
private static final long serialVersionUID = 3823509772499230844L;
+ /**
+ * Creates a {@link Pdf3DAnnotation} instance.
+ *
+ * @param rect the annotation rectangle, defining the location of the annotation on the page
+ * in default user space units. See {@link PdfAnnotation#setRectangle(PdfArray)}.
+ * @param artwork 3D artwork which is represented by the annotation
+ */
public Pdf3DAnnotation(Rectangle rect, PdfObject artwork) {
super(rect);
put(PdfName._3DD, artwork);
}
+ /**
+ * Instantiates a new {@link Pdf3DAnnotation} instance based on {@link PdfDictionary}
+ * instance, that represents existing annotation object in the document.
+ *
+ * @param pdfObject the {@link PdfDictionary} representing annotation object
+ * @see PdfAnnotation#makeAnnotation(PdfObject)
+ */
public Pdf3DAnnotation(PdfDictionary pdfObject) {
super(pdfObject);
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public PdfName getSubtype() {
return PdfName._3D;
}
+ /**
+ * Sets the default initial view of the 3D artwork that shall be used when the annotation is activated.
+ *
+ * @param initialView the default initial view of the 3D artwork that shall be used
+ * when the annotation is activated
+ * @return this {@link Pdf3DAnnotation} instance
+ */
public Pdf3DAnnotation setDefaultInitialView(PdfObject initialView) {
return (Pdf3DAnnotation) put(PdfName._3DV, initialView);
}
+ /**
+ * Gets the default initial view of the 3D artwork that shall be used when the annotation is activated.
+ *
+ * @return the default initial view of the 3D artwork that shall be used when the annotation is activated
+ */
public PdfObject getDefaultInitialView() {
return getPdfObject().get(PdfName._3DV);
}
+ /**
+ * Sets the activation dictionary that defines the times at which the annotation shall be
+ * activated and deactivated and the state of the 3D artwork instance at those times.
+ *
+ * @param activationDictionary dictionary that defines the times at which the annotation
+ * shall be activated and deactivated and the state of the 3D artwork
+ * instance at those times.
+ * @return this {@link Pdf3DAnnotation} instance
+ */
public Pdf3DAnnotation setActivationDictionary(PdfDictionary activationDictionary) {
return (Pdf3DAnnotation) put(PdfName._3DA, activationDictionary);
}
+ /**
+ * Gets the activation dictionary that defines the times at which the annotation shall be
+ * activated and deactivated and the state of the 3D artwork instance at those times.
+ *
+ * @return the activation dictionary that defines the times at which the annotation shall be
+ * activated and deactivated and the state of the 3D artwork instance at those times.
+ */
public PdfDictionary getActivationDictionary() {
return getPdfObject().getAsDictionary(PdfName._3DA);
}
+ /**
+ * Sets the primary use of the 3D annotation.
+ *
+ *
+ * If true, it is intended to be interactive; if false, it is intended to be manipulated programmatically,
+ * as with an ECMAScript animation. Interactive PDF processors may present different user interface controls
+ * for interactive 3D annotations (for example, to rotate, pan, or zoom the artwork) than for those
+ * managed by a script or other mechanism.
+ *
+ *
+ * Default value: true.
+ *
+ * @param interactive if true, it is intended to be interactive; if false, it is intended to be
+ * manipulated programmatically
+ * @return this {@link Pdf3DAnnotation} instance
+ */
public Pdf3DAnnotation setInteractive(boolean interactive) {
return (Pdf3DAnnotation) put(PdfName._3DI, PdfBoolean.valueOf(interactive));
}
+ /**
+ * Indicates whether the 3D annotation is intended to be interactive or not.
+ *
+ * @return whether the 3D annotation is intended to be interactive or not
+ */
public PdfBoolean isInteractive() {
return getPdfObject().getAsBoolean(PdfName._3DI);
}
+ /**
+ * Sets the 3D view box, which is the rectangular area in which the 3D artwork shall be drawn.
+ * It shall be within the rectangle specified by the annotation’s Rect entry and shall be expressed
+ * in the annotation’s target coordinate system.
+ *
+ *
+ * Default value: the annotation’s Rect entry, expressed in the target coordinate system.
+ * This value is [-w/2 -h/2 w/2 h/2], where w and h are the width and height, respectively, of Rect.
+ *
+ * @param viewBox the rectangular area in which the 3D artwork shall be drawn
+ * @return this {@link Pdf3DAnnotation} instance
+ */
public Pdf3DAnnotation setViewBox(Rectangle viewBox) {
return (Pdf3DAnnotation) put(PdfName._3DB, new PdfArray(viewBox));
}
+ /**
+ * Gets the 3D view box, which is the rectangular area in which the 3D artwork shall be drawn.
+ *
+ * @return the 3D view box, which is the rectangular area in which the 3D artwork shall be drawn.
+ */
public Rectangle getViewBox() {
return getPdfObject().getAsRectangle(PdfName._3DB);
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/da/AnnotationDefaultAppearance.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/da/AnnotationDefaultAppearance.java
index 3b628ee2f7..2c730b4bb7 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/da/AnnotationDefaultAppearance.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/annot/da/AnnotationDefaultAppearance.java
@@ -53,7 +53,16 @@ This file is part of the iText (R) project.
import java.util.Map;
/**
- * Helper class for setting
+ * Helper class for setting annotation default appearance. The class provides setters for
+ * font color, font size and font itself.
+ *
+ *
+ * Note that only standard font names that do not require font resources are supported.
+ *
+ *
+ * Note that it is possible to create annotation with custom font name in DA, but this require
+ * manual resource modifications (you have to put font in DR of AcroForm and use
+ * its resource name in DA) and only Acrobat supports that workflow.
*/
public class AnnotationDefaultAppearance {
@@ -92,41 +101,93 @@ public class AnnotationDefaultAppearance {
private String rawFontName = "/Helv";
private float fontSize = 0;
+ /**
+ * Creates the default instance of {@link AnnotationDefaultAppearance}.
+ *
+ *
+ * The default font is {@link StandardAnnotationFont#Helvetica}. The default font size is 12.
+ */
public AnnotationDefaultAppearance() {
setFont(StandardAnnotationFont.Helvetica);
setFontSize(12);
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font.
+ *
+ * @param font one of {@link StandardAnnotationFont standard annotation fonts} to be set as
+ * the default one for this {@link AnnotationDefaultAppearance}
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setFont(StandardAnnotationFont font) {
setRawFontName(stdAnnotFontNames.get(font));
return this;
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font.
+ *
+ * @param font one of {@link ExtendedAnnotationFont extended annotation fonts} to be set as
+ * the default one for this {@link AnnotationDefaultAppearance}
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setFont(ExtendedAnnotationFont font) {
setRawFontName(extAnnotFontNames.get(font));
return this;
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font size.
+ *
+ * @param fontSize font size to be set as the {@link AnnotationDefaultAppearance}'s default font size
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setFontSize(float fontSize) {
this.fontSize = fontSize;
return this;
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font color.
+ *
+ * @param rgbColor {@link DeviceRgb} to be set as the {@link AnnotationDefaultAppearance}'s
+ * default font color
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setColor(DeviceRgb rgbColor) {
setColorOperand(rgbColor.getColorValue(), "rg");
return this;
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font color.
+ *
+ * @param cmykColor {@link DeviceCmyk} to be set as the {@link AnnotationDefaultAppearance}'s
+ * default font color
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setColor(DeviceCmyk cmykColor) {
setColorOperand(cmykColor.getColorValue(), "k");
return this;
}
+ /**
+ * Sets the {@link AnnotationDefaultAppearance}'s default font color.
+ *
+ * @param grayColor {@link DeviceGray} to be set as the {@link AnnotationDefaultAppearance}'s
+ * default font color
+ * @return this {@link AnnotationDefaultAppearance}
+ */
public AnnotationDefaultAppearance setColor(DeviceGray grayColor) {
setColorOperand(grayColor.getColorValue(), "g");
return this;
}
+ /**
+ * Gets the {@link AnnotationDefaultAppearance}'s representation as {@link PdfString}.
+ *
+ * @return the {@link PdfString} representation of this {@link AnnotationDefaultAppearance}
+ */
public PdfString toPdfString() {
return new PdfString(MessageFormatUtil.format("{0} {1} Tf {2}", rawFontName, fontSize, colorOperand));
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/PdfCanvas.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/PdfCanvas.java
index d096a28f8e..8076632dd9 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/PdfCanvas.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/PdfCanvas.java
@@ -1036,17 +1036,27 @@ public PdfCanvas curveFromTo(double x1, double y1, double x3, double y3) {
*/
public PdfCanvas arc(double x1, double y1, double x2, double y2,
double startAng, double extent) {
- List ar = bezierArc(x1, y1, x2, y2, startAng, extent);
- if (ar.isEmpty())
- return this;
- double[] pt = ar.get(0);
- moveTo(pt[0], pt[1]);
- for (int i = 0; i < ar.size(); ++i) {
- pt = ar.get(i);
- curveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]);
- }
+ return drawArc(x1, y1, x2, y2, startAng, extent, false);
+ }
- return this;
+ /**
+ * Draws a partial ellipse with the preceding line to the start of the arc to prevent path
+ * broking. The target arc is inscribed within the rectangle x1,y1,x2,y2, starting
+ * at startAng degrees and covering extent degrees. Angles start with 0 to the right (+x)
+ * and increase counter-clockwise.
+ *
+ * @param x1 a corner of the enclosing rectangle
+ * @param y1 a corner of the enclosing rectangle
+ * @param x2 a corner of the enclosing rectangle
+ * @param y2 a corner of the enclosing rectangle
+ * @param startAng starting angle in degrees
+ * @param extent angle extent in degrees
+ *
+ * @return the current canvas
+ */
+ public PdfCanvas arcContinuous(double x1, double y1, double x2, double y2,
+ double startAng, double extent) {
+ return drawArc(x1, y1, x2, y2, startAng, extent, true);
}
/**
@@ -2069,7 +2079,6 @@ public PdfXObject addImageAt(ImageData image, float x, float y, boolean asInline
public PdfXObject addImage(ImageData image, float x, float y, float width, boolean asInline) {
if (image.getOriginalType() == ImageType.WMF) {
WmfImageHelper wmf = new WmfImageHelper(image);
- // TODO add matrix parameters
PdfXObject xObject = wmf.createFormXObject(document);
addImageWithTransformationMatrix(xObject, width, 0, 0, width, x, y);
return xObject;
@@ -2789,6 +2798,26 @@ private void applyRotation(PdfPage page) {
}
}
+ private PdfCanvas drawArc(double x1, double y1, double x2, double y2,
+ double startAng, double extent, boolean continuous) {
+ List ar = bezierArc(x1, y1, x2, y2, startAng, extent);
+ if (ar.isEmpty()) {
+ return this;
+ }
+
+ double[] pt = ar.get(0);
+ if (continuous) {
+ lineTo(pt[0], pt[1]);
+ } else {
+ moveTo(pt[0], pt[1]);
+ }
+ for (int index = 0; index < ar.size(); ++index) {
+ pt = ar.get(index);
+ curveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]);
+ }
+ return this;
+ }
+
private static PdfStream getPageStream(PdfPage page) {
PdfStream stream = page.getLastContentStream();
return stream == null || stream.getOutputStream() == null || stream.containsKey(PdfName.Filter) ? page.newContentStreamAfter() : stream;
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/data/TextRenderInfo.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/data/TextRenderInfo.java
index 8f691d38d2..10ced895a6 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/data/TextRenderInfo.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/data/TextRenderInfo.java
@@ -43,6 +43,7 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.kernel.pdf.canvas.parser.data;
+import com.itextpdf.io.font.FontProgram;
import com.itextpdf.io.font.otf.GlyphLine;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.font.PdfFont;
@@ -78,7 +79,6 @@ public class TextRenderInfo extends AbstractRenderInfo {
private final Matrix textToUserSpaceTransformMatrix;
private final Matrix textMatrix;
private float unscaledWidth = Float.NaN;
- private double[] fontMatrix = null;
/**
* Hierarchy of nested canvas tags for the text from the most inner (nearest to text) tag to the most outer.
@@ -99,11 +99,10 @@ public TextRenderInfo(PdfString str, CanvasGraphicsState gs, Matrix textMatrix,
this.textToUserSpaceTransformMatrix = textMatrix.multiply(gs.getCtm());
this.textMatrix = textMatrix;
this.canvasTagHierarchy = Collections.unmodifiableList(new ArrayList<>(canvasTagHierarchy));
- this.fontMatrix = gs.getFont().getFontMatrix();
}
/**
- * Used for creating sub-TextRenderInfos for each individual character
+ * Used for creating sub-TextRenderInfos for each individual character.
*
* @param parent the parent TextRenderInfo
* @param str the content of a TextRenderInfo
@@ -116,10 +115,11 @@ private TextRenderInfo(TextRenderInfo parent, PdfString str, float horizontalOff
this.textToUserSpaceTransformMatrix = offsetMatrix.multiply(parent.textToUserSpaceTransformMatrix);
this.textMatrix = offsetMatrix.multiply(parent.textMatrix);
this.canvasTagHierarchy = parent.canvasTagHierarchy;
- this.fontMatrix = parent.gs.getFont().getFontMatrix();
}
/**
+ * Gets the text to be rendered according to canvas operators.
+ *
* @return the text to render
*/
public String getText() {
@@ -465,7 +465,7 @@ private float getUnscaledFontSpaceWidth() {
if (charWidth == 0) {
charWidth = gs.getFont().getFontProgram().getAvgWidth();
}
- float w = (float) (charWidth * fontMatrix[0]);
+ float w = (float) ((double) charWidth / FontProgram.UNITS_NORMALIZATION);
return (w * gs.getFontSize() + gs.getCharSpacing() + gs.getWordSpacing()) * gs.getHorizontalScaling() / 100f;
}
@@ -501,7 +501,7 @@ private float[] getWidthAndWordSpacing(PdfString string) {
checkGraphicsState();
float[] result = new float[2];
- result[0] = (float) ((gs.getFont().getContentWidth(string) * fontMatrix[0]));
+ result[0] = (float) ((double) gs.getFont().getContentWidth(string) / FontProgram.UNITS_NORMALIZATION);
result[1] = " ".equals(string.getValue()) ? gs.getWordSpacing() : 0;
return result;
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtils.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtils.java
index b609448966..be8e8012a8 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtils.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtils.java
@@ -166,6 +166,39 @@ public static PdfStream parse(PdfCanvasParser ps, PdfDictionary colorSpaceDic) t
return inlineImageAsStreamObject;
}
+ /**
+ * @param colorSpaceName the name of the color space. If null, a bi-tonal (black and white) color space is assumed.
+ * @return the components per pixel for the specified color space
+ */
+ static int getComponentsPerPixel(PdfName colorSpaceName, PdfDictionary colorSpaceDic) {
+ if (colorSpaceName == null)
+ return 1;
+ if (colorSpaceName.equals(PdfName.DeviceGray))
+ return 1;
+ if (colorSpaceName.equals(PdfName.DeviceRGB))
+ return 3;
+ if (colorSpaceName.equals(PdfName.DeviceCMYK))
+ return 4;
+
+ if (colorSpaceDic != null) {
+ PdfArray colorSpace = colorSpaceDic.getAsArray(colorSpaceName);
+ if (colorSpace != null) {
+ if (PdfName.Indexed.equals(colorSpace.getAsName(0))) {
+ return 1;
+ } else if (PdfName.ICCBased.equals(colorSpace.getAsName(0))) {
+ return colorSpace.getAsStream(1).getAsNumber(PdfName.N).intValue();
+ }
+ } else {
+ PdfName tempName = colorSpaceDic.getAsName(colorSpaceName);
+ if (tempName != null) {
+ return getComponentsPerPixel(tempName, colorSpaceDic);
+ }
+ }
+ }
+
+ throw new InlineImageParseException(PdfException.UnexpectedColorSpace1).setMessageParams(colorSpaceName);
+ }
+
/**
* Parses the next inline image dictionary from the parser. The parser must be positioned immediately following the BI operator.
* The parser will be left with position immediately following the whitespace character that follows the ID operator that ends the inline image dictionary.
@@ -226,37 +259,6 @@ private static PdfObject getAlternateValue(PdfName key, PdfObject value) {
return value;
}
- /**
- * @param colorSpaceName the name of the color space. If null, a bi-tonal (black and white) color space is assumed.
- * @return the components per pixel for the specified color space
- */
- private static int getComponentsPerPixel(PdfName colorSpaceName, PdfDictionary colorSpaceDic) {
- if (colorSpaceName == null)
- return 1;
- if (colorSpaceName.equals(PdfName.DeviceGray))
- return 1;
- if (colorSpaceName.equals(PdfName.DeviceRGB))
- return 3;
- if (colorSpaceName.equals(PdfName.DeviceCMYK))
- return 4;
-
- if (colorSpaceDic != null) {
- PdfArray colorSpace = colorSpaceDic.getAsArray(colorSpaceName);
- if (colorSpace != null) {
- if (PdfName.Indexed.equals(colorSpace.getAsName(0))) {
- return 1;
- }
- } else {
- PdfName tempName = colorSpaceDic.getAsName(colorSpaceName);
- if (tempName != null) {
- return getComponentsPerPixel(tempName, colorSpaceDic);
- }
- }
- }
-
- throw new InlineImageParseException(PdfException.UnexpectedColorSpace1).setMessageParams(colorSpaceName);
- }
-
/**
* Computes the number of unfiltered bytes that each row of the image will contain.
* If the number of bytes results in a partial terminating byte, this number is rounded up
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/filespec/PdfFileSpec.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/filespec/PdfFileSpec.java
index 17bf323494..47c91961b2 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/filespec/PdfFileSpec.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/filespec/PdfFileSpec.java
@@ -387,6 +387,7 @@ private static PdfFileSpec createEmbeddedFileSpec(PdfDocument doc, PdfStream str
ef.put(PdfName.F, stream);
ef.put(PdfName.UF, stream);
dict.put(PdfName.EF, ef);
+ doc.markStreamAsEmbeddedFile(stream);
return (PdfFileSpec) new PdfFileSpec(dict).makeIndirect(doc);
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/PdfStructTreeRoot.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/PdfStructTreeRoot.java
index 1dbec30ba8..01e93a8e89 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/PdfStructTreeRoot.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagging/PdfStructTreeRoot.java
@@ -68,6 +68,9 @@ This file is part of the iText (R) project.
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+/**
+ * Represents a wrapper-class for structure tree root dictionary. See ISO-32000-1 "14.7.2 Structure hierarchy".
+ */
public class PdfStructTreeRoot extends PdfObjectWrapper implements IStructureNode {
private static final long serialVersionUID = 2168384302241193868L;
@@ -77,21 +80,40 @@ public class PdfStructTreeRoot extends PdfObjectWrapper implement
private static Map staticRoleNames = new ConcurrentHashMap<>();
+ /**
+ * Creates a new structure tree root instance, this initializes empty logical structure in the document.
+ * This class also handles global state of parent tree, so it's not expected to create multiple instances
+ * of this class. Instead, use {@link PdfDocument#getStructTreeRoot()}.
+ *
+ * @param document a document to which new instance of struct tree root will be bound
+ */
public PdfStructTreeRoot(PdfDocument document) {
this((PdfDictionary) new PdfDictionary().makeIndirect(document), document);
getPdfObject().put(PdfName.Type, PdfName.StructTreeRoot);
}
- public PdfStructTreeRoot(PdfDictionary pdfObject, PdfDocument document) {
- super(pdfObject);
+ /**
+ * Creates wrapper instance for already existing logical structure tree root in the document.
+ * This class also handles global state of parent tree, so it's not expected to create multiple instances
+ * of this class. Instead, use {@link PdfDocument#getStructTreeRoot()}.
+ *
+ * @param structTreeRootDict a dictionary that defines document structure tree root
+ * @param document a document, which contains given structure tree root dictionary
+ */
+ public PdfStructTreeRoot(PdfDictionary structTreeRootDict, PdfDocument document) {
+ super(structTreeRootDict);
this.document = document;
if (this.document == null) {
- ensureObjectIsAddedToDocument(pdfObject);
- this.document = pdfObject.getIndirectReference().getDocument();
+ ensureObjectIsAddedToDocument(structTreeRootDict);
+ this.document = structTreeRootDict.getIndirectReference().getDocument();
}
setForbidRelease();
parentTreeHandler = new ParentTreeHandler(this);
- // TODO may be remove?
+
+ // Always init role map dictionary in order to avoid inconsistency, because
+ // iText often initializes it during role mapping resolution anyway.
+ // In future, better way might be to not write it to the document needlessly
+ // and avoid possible redundant modifications in append mode.
getRoleMap();
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java
index 6fcc32d1b8..71ff994d89 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagStructureContext.java
@@ -643,7 +643,8 @@ private void removePageTagFromParent(IStructureNode pageTag, IStructureNode pare
removePageTagFromParent(structParent, parent.getParent());
PdfIndirectReference indRef = parentStructDict.getIndirectReference();
if (indRef != null) {
- // TODO how about possible references to structure element from refs or structure destination for instance?
+ // TODO DEVSIX-5472 need to clean references to structure element from
+ // other structure elements /Ref entries and structure destinations
indRef.setFree();
}
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagTreePointer.java b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagTreePointer.java
index 272179b549..423e20d9d9 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagTreePointer.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/pdf/tagutils/TagTreePointer.java
@@ -359,7 +359,8 @@ public TagTreePointer removeTag() {
PdfIndirectReference indRef = currentStructElem.getPdfObject().getIndirectReference();
if (indRef != null) {
- // TODO how about possible references to structure element from refs or structure destination for instance?
+ // TODO DEVSIX-5472 need to clean references to structure element from
+ // other structure elements /Ref entries and structure destinations
indRef.setFree();
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/CompareTool.java b/kernel/src/main/java/com/itextpdf/kernel/utils/CompareTool.java
index 8b6f7c90c1..a55a70a3e6 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/utils/CompareTool.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/utils/CompareTool.java
@@ -718,11 +718,12 @@ public String compareXmp(String outPdf, String cmpPdf) {
*/
public String compareXmp(String outPdf, String cmpPdf, boolean ignoreDateAndProducerProperties) {
init(outPdf, cmpPdf);
- PdfDocument cmpDocument = null;
- PdfDocument outDocument = null;
- try {
- cmpDocument = new PdfDocument(new PdfReader(this.cmpPdf), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- outDocument = new PdfDocument(new PdfReader(this.outPdf), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ try (PdfReader readerCmp = new PdfReader(this.cmpPdf);
+ PdfDocument cmpDocument = new PdfDocument(readerCmp,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ PdfReader readerOut = new PdfReader(this.outPdf);
+ PdfDocument outDocument = new PdfDocument(readerOut,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo))) {
byte[] cmpBytes = cmpDocument.getXmpMetadata(), outBytes = outDocument.getXmpMetadata();
if (ignoreDateAndProducerProperties) {
XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(cmpBytes, new ParseOptions().setOmitNormalization(true));
@@ -748,11 +749,6 @@ public String compareXmp(String outPdf, String cmpPdf, boolean ignoreDateAndProd
}
} catch (Exception ex) {
return "XMP parsing failure!";
- } finally {
- if (cmpDocument != null)
- cmpDocument.close();
- if (outDocument != null)
- outDocument.close();
}
return null;
}
@@ -809,19 +805,21 @@ public String compareDocumentInfo(String outPdf, String cmpPdf, byte[] outPass,
System.out.print("[itext] INFO Comparing document info.......");
String message = null;
setPassword(outPass, cmpPass);
- PdfDocument outDocument = new PdfDocument(new PdfReader(outPdf, getOutReaderProperties()), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- PdfDocument cmpDocument = new PdfDocument(new PdfReader(cmpPdf, getCmpReaderProperties()), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- String[] cmpInfo = convertInfo(cmpDocument.getDocumentInfo());
- String[] outInfo = convertInfo(outDocument.getDocumentInfo());
- for (int i = 0; i < cmpInfo.length; ++i) {
- if (!cmpInfo[i].equals(outInfo[i])) {
- message = MessageFormatUtil.format("Document info fail. Expected: \"{0}\", actual: \"{1}\"", cmpInfo[i], outInfo[i]);
- break;
+ try (PdfReader readerOut = new PdfReader(outPdf, getOutReaderProperties());
+ PdfDocument outDocument = new PdfDocument(readerOut,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ PdfReader readerCmp = new PdfReader(cmpPdf, getCmpReaderProperties());
+ PdfDocument cmpDocument = new PdfDocument(readerCmp,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo))) {
+ String[] cmpInfo = convertInfo(cmpDocument.getDocumentInfo());
+ String[] outInfo = convertInfo(outDocument.getDocumentInfo());
+ for (int i = 0; i < cmpInfo.length; ++i) {
+ if (!cmpInfo[i].equals(outInfo[i])) {
+ message = MessageFormatUtil.format("Document info fail. Expected: \"{0}\", actual: \"{1}\"", cmpInfo[i], outInfo[i]);
+ break;
+ }
}
}
- outDocument.close();
- cmpDocument.close();
-
if (message == null)
System.out.println("OK");
else
@@ -853,25 +851,28 @@ public String compareDocumentInfo(String outPdf, String cmpPdf) throws IOExcepti
public String compareLinkAnnotations(String outPdf, String cmpPdf) throws IOException {
System.out.print("[itext] INFO Comparing link annotations....");
String message = null;
- PdfDocument outDocument = new PdfDocument(new PdfReader(outPdf), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- PdfDocument cmpDocument = new PdfDocument(new PdfReader(cmpPdf), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- for (int i = 0; i < outDocument.getNumberOfPages() && i < cmpDocument.getNumberOfPages(); i++) {
- List outLinks = getLinkAnnotations(i + 1, outDocument);
- List cmpLinks = getLinkAnnotations(i + 1, cmpDocument);
-
- if (cmpLinks.size() != outLinks.size()) {
- message = MessageFormatUtil.format("Different number of links on page {0}.", i + 1);
- break;
- }
- for (int j = 0; j < cmpLinks.size(); j++) {
- if (!compareLinkAnnotations(cmpLinks.get(j), outLinks.get(j), cmpDocument, outDocument)) {
- message = MessageFormatUtil.format("Different links on page {0}.\n{1}\n{2}", i + 1, cmpLinks.get(j).toString(), outLinks.get(j).toString());
+ try (PdfReader readerOut = new PdfReader(outPdf);
+ PdfDocument outDocument = new PdfDocument(readerOut,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ PdfReader readerCmp = new PdfReader(cmpPdf);
+ PdfDocument cmpDocument = new PdfDocument(readerCmp,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo))){
+ for (int i = 0; i < outDocument.getNumberOfPages() && i < cmpDocument.getNumberOfPages(); i++) {
+ List outLinks = getLinkAnnotations(i + 1, outDocument);
+ List cmpLinks = getLinkAnnotations(i + 1, cmpDocument);
+
+ if (cmpLinks.size() != outLinks.size()) {
+ message = MessageFormatUtil.format("Different number of links on page {0}.", i + 1);
break;
}
+ for (int j = 0; j < cmpLinks.size(); j++) {
+ if (!compareLinkAnnotations(cmpLinks.get(j), outLinks.get(j), cmpDocument, outDocument)) {
+ message = MessageFormatUtil.format("Different links on page {0}.\n{1}\n{2}", i + 1, cmpLinks.get(j).toString(), outLinks.get(j).toString());
+ break;
+ }
+ }
}
}
- outDocument.close();
- cmpDocument.close();
if (message == null)
System.out.println("OK");
else
@@ -902,20 +903,18 @@ public String compareTagStructures(String outPdf, String cmpPdf) throws IOExcept
String cmpXmlPath = outPdf.replace(".pdf", ".cmp.xml");
String message = null;
-
- PdfReader readerOut = new PdfReader(outPdf);
- PdfDocument docOut = new PdfDocument(readerOut, new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- FileOutputStream xmlOut = new FileOutputStream(outXmlPath);
- new TaggedPdfReaderTool(docOut).setRootTag("root").convertToXml(xmlOut);
- docOut.close();
- xmlOut.close();
-
- PdfReader readerCmp = new PdfReader(cmpPdf);
- PdfDocument docCmp = new PdfDocument(readerCmp, new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- FileOutputStream xmlCmp = new FileOutputStream(cmpXmlPath);
- new TaggedPdfReaderTool(docCmp).setRootTag("root").convertToXml(xmlCmp);
- docCmp.close();
- xmlCmp.close();
+ try (PdfReader readerOut = new PdfReader(outPdf);
+ PdfDocument docOut = new PdfDocument(readerOut,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ FileOutputStream xmlOut = new FileOutputStream(outXmlPath)) {
+ new TaggedPdfReaderTool(docOut).setRootTag("root").convertToXml(xmlOut);
+ }
+ try (PdfReader readerCmp = new PdfReader(cmpPdf);
+ PdfDocument docCmp = new PdfDocument(readerCmp,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ FileOutputStream xmlCmp = new FileOutputStream(cmpXmlPath)) {
+ new TaggedPdfReaderTool(docCmp).setRootTag("root").convertToXml(xmlCmp);
+ }
if (!compareXmls(outXmlPath, cmpXmlPath)) {
message = "The tag structures are different.";
@@ -1000,7 +999,7 @@ private String compareVisually(String outPath, String differenceImagePrefix, Map
GhostscriptHelper ghostscriptHelper = null;
try {
- ghostscriptHelper = new GhostscriptHelper(gsExec);
+ ghostscriptHelper = new GhostscriptHelper(gsExec);
} catch (IllegalArgumentException e) {
throw new CompareToolExecutionException(e.getMessage());
}
@@ -1094,36 +1093,34 @@ private String listDiffPagesAsString(List diffPages) {
}
private void createIgnoredAreasPdfs(String outPath, Map> ignoredAreas) throws IOException {
- PdfWriter outWriter = new PdfWriter(outPath + IGNORED_AREAS_PREFIX + outPdfName);
- PdfWriter cmpWriter = new PdfWriter(outPath + IGNORED_AREAS_PREFIX + cmpPdfName);
-
StampingProperties properties = new StampingProperties();
properties.setEventCountingMetaInfo(metaInfo);
- PdfDocument pdfOutDoc = new PdfDocument(new PdfReader(outPdf), outWriter, properties);
- PdfDocument pdfCmpDoc = new PdfDocument(new PdfReader(cmpPdf), cmpWriter, properties);
-
- for (Map.Entry> entry : ignoredAreas.entrySet()) {
- int pageNumber = entry.getKey();
- List rectangles = entry.getValue();
-
- if (rectangles != null && !rectangles.isEmpty()) {
- PdfCanvas outCanvas = new PdfCanvas(pdfOutDoc.getPage(pageNumber));
- PdfCanvas cmpCanvas = new PdfCanvas(pdfCmpDoc.getPage(pageNumber));
-
- outCanvas.saveState();
- cmpCanvas.saveState();
- for (Rectangle rect : rectangles) {
- outCanvas.rectangle(rect).fill();
- cmpCanvas.rectangle(rect).fill();
+ try (PdfWriter outWriter = new PdfWriter(outPath + IGNORED_AREAS_PREFIX + outPdfName);
+ PdfReader readerOut = new PdfReader(outPdf);
+ PdfDocument pdfOutDoc = new PdfDocument(readerOut, outWriter, properties);
+ PdfWriter cmpWriter = new PdfWriter(outPath + IGNORED_AREAS_PREFIX + cmpPdfName);
+ PdfReader readerCmp = new PdfReader(cmpPdf);
+ PdfDocument pdfCmpDoc = new PdfDocument(readerCmp, cmpWriter, properties)) {
+ for (Map.Entry> entry : ignoredAreas.entrySet()) {
+ int pageNumber = entry.getKey();
+ List rectangles = entry.getValue();
+
+ if (rectangles != null && !rectangles.isEmpty()) {
+ PdfCanvas outCanvas = new PdfCanvas(pdfOutDoc.getPage(pageNumber));
+ PdfCanvas cmpCanvas = new PdfCanvas(pdfCmpDoc.getPage(pageNumber));
+
+ outCanvas.saveState();
+ cmpCanvas.saveState();
+ for (Rectangle rect : rectangles) {
+ outCanvas.rectangle(rect).fill();
+ cmpCanvas.rectangle(rect).fill();
+ }
+ outCanvas.restoreState();
+ cmpCanvas.restoreState();
}
- outCanvas.restoreState();
- cmpCanvas.restoreState();
}
}
- pdfOutDoc.close();
- pdfCmpDoc.close();
-
init(outPath + IGNORED_AREAS_PREFIX + outPdfName, outPath + IGNORED_AREAS_PREFIX + cmpPdfName);
}
@@ -1161,69 +1158,61 @@ private void printOutCmpDirectories() {
private String compareByContent(String outPath, String differenceImagePrefix, Map> ignoredAreas) throws InterruptedException, IOException {
printOutCmpDirectories();
System.out.print("Comparing by content..........");
- PdfDocument outDocument;
- try {
- outDocument = new PdfDocument(new PdfReader(outPdf, getOutReaderProperties()), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- } catch (IOException e) {
- throw new IOException("File \"" + outPdf + "\" not found", e);
- }
- List outPages = new ArrayList<>();
- outPagesRef = new ArrayList<>();
- loadPagesFromReader(outDocument, outPages, outPagesRef);
-
- PdfDocument cmpDocument;
- try {
- cmpDocument = new PdfDocument(new PdfReader(cmpPdf, getCmpReaderProperties()), new DocumentProperties().setEventCountingMetaInfo(metaInfo));
- } catch (IOException e) {
- throw new IOException("File \"" + cmpPdf + "\" not found", e);
- }
- List cmpPages = new ArrayList<>();
- cmpPagesRef = new ArrayList<>();
- loadPagesFromReader(cmpDocument, cmpPages, cmpPagesRef);
-
- if (outPages.size() != cmpPages.size())
- return compareVisuallyAndCombineReports("Documents have different numbers of pages.", outPath, differenceImagePrefix, ignoredAreas, null);
-
- CompareResult compareResult = new CompareResult(compareByContentErrorsLimit);
- List equalPages = new ArrayList<>(cmpPages.size());
- for (int i = 0; i < cmpPages.size(); i++) {
- ObjectPath currentPath = new ObjectPath(cmpPagesRef.get(i), outPagesRef.get(i));
- if (compareDictionariesExtended(outPages.get(i), cmpPages.get(i), currentPath, compareResult))
- equalPages.add(i);
- }
-
- ObjectPath catalogPath = new ObjectPath(cmpDocument.getCatalog().getPdfObject().getIndirectReference(),
- outDocument.getCatalog().getPdfObject().getIndirectReference());
- Set ignoredCatalogEntries = new LinkedHashSet<>(Arrays.asList(PdfName.Pages, PdfName.Metadata));
- compareDictionariesExtended(outDocument.getCatalog().getPdfObject(), cmpDocument.getCatalog().getPdfObject(),
- catalogPath, compareResult, ignoredCatalogEntries);
-
- if (encryptionCompareEnabled) {
- compareDocumentsEncryption(outDocument, cmpDocument, compareResult);
- }
-
- outDocument.close();
- cmpDocument.close();
+ try (PdfReader readerOut = new PdfReader(outPdf, getOutReaderProperties());
+ PdfDocument outDocument = new PdfDocument(readerOut,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo));
+ PdfReader readerCmp = new PdfReader(cmpPdf, getCmpReaderProperties());
+ PdfDocument cmpDocument = new PdfDocument(readerCmp,
+ new DocumentProperties().setEventCountingMetaInfo(metaInfo))) {
+
+ List outPages = new ArrayList<>();
+ outPagesRef = new ArrayList<>();
+ loadPagesFromReader(outDocument, outPages, outPagesRef);
+
+ List cmpPages = new ArrayList<>();
+ cmpPagesRef = new ArrayList<>();
+ loadPagesFromReader(cmpDocument, cmpPages, cmpPagesRef);
+
+ if (outPages.size() != cmpPages.size())
+ return compareVisuallyAndCombineReports("Documents have different numbers of pages.", outPath, differenceImagePrefix, ignoredAreas, null);
+
+ CompareResult compareResult = new CompareResult(compareByContentErrorsLimit);
+ List equalPages = new ArrayList<>(cmpPages.size());
+ for (int i = 0; i < cmpPages.size(); i++) {
+ ObjectPath currentPath = new ObjectPath(cmpPagesRef.get(i), outPagesRef.get(i));
+ if (compareDictionariesExtended(outPages.get(i), cmpPages.get(i), currentPath, compareResult))
+ equalPages.add(i);
+ }
+
+ ObjectPath catalogPath = new ObjectPath(cmpDocument.getCatalog().getPdfObject().getIndirectReference(),
+ outDocument.getCatalog().getPdfObject().getIndirectReference());
+ Set ignoredCatalogEntries = new LinkedHashSet<>(Arrays.asList(PdfName.Pages, PdfName.Metadata));
+ compareDictionariesExtended(outDocument.getCatalog().getPdfObject(), cmpDocument.getCatalog().getPdfObject(),
+ catalogPath, compareResult, ignoredCatalogEntries);
+
+ if (encryptionCompareEnabled) {
+ compareDocumentsEncryption(outDocument, cmpDocument, compareResult);
+ }
+ if (generateCompareByContentXmlReport) {
+ String outPdfName = new File(outPdf).getName();
+ FileOutputStream xml = new FileOutputStream(outPath + "/" + outPdfName.substring(0, outPdfName.length() - 3) + "report.xml");
+ try {
+ compareResult.writeReportToXml(xml);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ xml.close();
+ }
- if (generateCompareByContentXmlReport) {
- String outPdfName = new File(outPdf).getName();
- FileOutputStream xml = new FileOutputStream(outPath + "/" + outPdfName.substring(0, outPdfName.length() - 3) + "report.xml");
- try {
- compareResult.writeReportToXml(xml);
- } catch (Exception e) {
- throw new RuntimeException(e.getMessage(), e);
- } finally {
- xml.close();
}
- }
-
- if (equalPages.size() == cmpPages.size() && compareResult.isOk()) {
- System.out.println("OK");
- System.out.flush();
- return null;
- } else {
- return compareVisuallyAndCombineReports(compareResult.getReport(), outPath, differenceImagePrefix, ignoredAreas, equalPages);
+ if (equalPages.size() == cmpPages.size() && compareResult.isOk()) {
+ System.out.println("OK");
+ System.out.flush();
+ return null;
+ } else {
+ return compareVisuallyAndCombineReports(compareResult.getReport(), outPath, differenceImagePrefix, ignoredAreas, equalPages);
+ }
}
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/DefaultSafeXmlParserFactory.java b/kernel/src/main/java/com/itextpdf/kernel/utils/DefaultSafeXmlParserFactory.java
new file mode 100644
index 0000000000..2d54edc76d
--- /dev/null
+++ b/kernel/src/main/java/com/itextpdf/kernel/utils/DefaultSafeXmlParserFactory.java
@@ -0,0 +1,192 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.utils;
+
+import com.itextpdf.io.util.MessageFormatUtil;
+import com.itextpdf.kernel.KernelLogMessageConstant;
+import com.itextpdf.kernel.PdfException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Implementation of {@link IXmlParserFactory} for creating safe xml parser objects.
+ * Creates parsers with configuration to prevent XML bombs and XXE attacks.
+ */
+public class DefaultSafeXmlParserFactory implements IXmlParserFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSafeXmlParserFactory.class);
+
+ /**
+ * Feature for disallowing DOCTYPE declaration.
+ *
+ *
+ * Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+ */
+ private final static String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
+
+ /**
+ * If you can't disable DOCTYPE declarations, then at least disable external entities.
+ * Must be used with the {@link DefaultSafeXmlParserFactory#EXTERNAL_PARAMETER_ENTITIES}, otherwise has no effect.
+ *
+ *
+ * Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+ * Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+ * JDK7+ - http://xml.org/sax/features/external-general-entities
+ */
+ private final static String EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
+
+ /**
+ * Must be used with the {@link DefaultSafeXmlParserFactory#EXTERNAL_GENERAL_ENTITIES}, otherwise has no effect.
+ *
+ *
+ * Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+ * Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+ * JDK7+ - http://xml.org/sax/features/external-parameter-entities
+ */
+ private final static String EXTERNAL_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
+
+ /**
+ * Disable external DTDs.
+ */
+ private final static String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+
+ /**
+ * Creates instance of {@link DefaultSafeXmlParserFactory}.
+ */
+ public DefaultSafeXmlParserFactory() {
+ // empty constructor
+ }
+
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ configureSafeDocumentBuilderFactory(factory);
+ factory.setNamespaceAware(namespaceAware);
+ factory.setIgnoringComments(ignoringComments);
+ DocumentBuilder db;
+ try {
+ db = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+ db.setEntityResolver(new SafeEmptyEntityResolver());
+ return db;
+ }
+
+ @Override
+ public XMLReader createXMLReaderInstance(boolean namespaceAware, boolean validating) {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(namespaceAware);
+ factory.setValidating(validating);
+ configureSafeSAXParserFactory(factory);
+ XMLReader xmlReader;
+ try {
+ SAXParser saxParser = factory.newSAXParser();
+ xmlReader = saxParser.getXMLReader();
+ } catch (ParserConfigurationException | SAXException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+ xmlReader.setEntityResolver(new SafeEmptyEntityResolver());
+ return xmlReader;
+ }
+
+ private void configureSafeDocumentBuilderFactory(DocumentBuilderFactory factory) {
+ tryToSetFeature(factory, DISALLOW_DOCTYPE_DECL, true);
+ tryToSetFeature(factory, EXTERNAL_GENERAL_ENTITIES, false);
+ tryToSetFeature(factory, EXTERNAL_PARAMETER_ENTITIES, false);
+ tryToSetFeature(factory, LOAD_EXTERNAL_DTD, false);
+ // recommendations from Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+ factory.setXIncludeAware(false);
+ factory.setExpandEntityReferences(false);
+ }
+
+ private void configureSafeSAXParserFactory(SAXParserFactory factory) {
+ tryToSetFeature(factory, DISALLOW_DOCTYPE_DECL, true);
+ tryToSetFeature(factory, EXTERNAL_GENERAL_ENTITIES, false);
+ tryToSetFeature(factory, EXTERNAL_PARAMETER_ENTITIES, false);
+ tryToSetFeature(factory, LOAD_EXTERNAL_DTD, false);
+ // recommendations from Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+ factory.setXIncludeAware(false);
+ }
+
+ private void tryToSetFeature(DocumentBuilderFactory factory, String feature, boolean value) {
+ try {
+ factory.setFeature(feature, value);
+ } catch (ParserConfigurationException e) {
+ LOGGER.info(MessageFormatUtil
+ .format(KernelLogMessageConstant.FEATURE_IS_NOT_SUPPORTED, e.getMessage(), feature));
+ }
+ }
+
+ private void tryToSetFeature(SAXParserFactory factory, String feature, boolean value) {
+ try {
+ factory.setFeature(feature, value);
+ } catch (ParserConfigurationException | SAXNotRecognizedException | SAXNotSupportedException e) {
+ LOGGER.info(MessageFormatUtil
+ .format(KernelLogMessageConstant.FEATURE_IS_NOT_SUPPORTED, e.getMessage(), feature));
+ }
+ }
+
+ // Prevents XXE attacks
+ private static class SafeEmptyEntityResolver implements EntityResolver {
+ public SafeEmptyEntityResolver() {
+ // empty constructor
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId) {
+ throw new PdfException(PdfException.ExternalEntityElementFoundInXml);
+ }
+ }
+}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/IXmlParserFactory.java b/kernel/src/main/java/com/itextpdf/kernel/utils/IXmlParserFactory.java
new file mode 100644
index 0000000000..57c3fa29c5
--- /dev/null
+++ b/kernel/src/main/java/com/itextpdf/kernel/utils/IXmlParserFactory.java
@@ -0,0 +1,72 @@
+/*
+
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: Bruno Lowagie, Paulo Soares, et al.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.utils;
+
+import javax.xml.parsers.DocumentBuilder;
+import org.xml.sax.XMLReader;
+
+/**
+ * The interface in which methods for creating xml parsers are declared.
+ */
+public interface IXmlParserFactory {
+ /**
+ * Creates the instance of the {@link DocumentBuilder}.
+ *
+ * @param namespaceAware specifies whether the parser should be namespace aware
+ * @param ignoringComments specifies whether the parser should ignore comments
+ *
+ * @return instance of the {@link DocumentBuilder}
+ */
+ DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments);
+
+ /**
+ * Creates the instance of the {@link XMLReader}.
+ *
+ * @param namespaceAware specifies whether the parser should be namespace aware
+ * @param validating specifies whether the parser should validate documents as they are parsed
+ *
+ * @return instance of the {@link XMLReader}
+ */
+ XMLReader createXMLReaderInstance(boolean namespaceAware, boolean validating);
+}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/XmlProcessorCreator.java b/kernel/src/main/java/com/itextpdf/kernel/utils/XmlProcessorCreator.java
new file mode 100644
index 0000000000..776ea8dd56
--- /dev/null
+++ b/kernel/src/main/java/com/itextpdf/kernel/utils/XmlProcessorCreator.java
@@ -0,0 +1,115 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: Bruno Lowagie, Paulo Soares, et al.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.utils;
+
+import javax.xml.parsers.DocumentBuilder;
+import org.xml.sax.XMLReader;
+
+/**
+ * Utility class for creating XML processors.
+ */
+public final class XmlProcessorCreator {
+
+ private static IXmlParserFactory xmlParserFactory;
+
+ static {
+ xmlParserFactory = new DefaultSafeXmlParserFactory();
+ }
+
+ private XmlProcessorCreator() {
+ }
+
+ /**
+ * Specifies an {@link IXmlParserFactory} implementation that will be used to create the xml
+ * parsers in the {@link XmlProcessorCreator}. Pass {@link DefaultSafeXmlParserFactory} to use default safe
+ * factory that should prevent XML attacks like XML bombs and XXE attacks. This will definitely
+ * throw an exception if the XXE object is present in the XML. Also it is configured to throw
+ * an exception even in case of any DTD in XML file, but this option depends on the parser
+ * implementation on your system, it may not work if your parser implementation
+ * does not support the corresponding functionality. In this case declare your own
+ * {@link IXmlParserFactory} implementation and pass it to this method.
+ *
+ * @param factory factory to be used to create xml parsers. If the passed factory is {@code null},
+ * the {@link DefaultSafeXmlParserFactory} will be used.
+ */
+ public static void setXmlParserFactory(IXmlParserFactory factory) {
+ if (factory == null) {
+ xmlParserFactory = new DefaultSafeXmlParserFactory();
+ } else {
+ xmlParserFactory = factory;
+ }
+ }
+
+ /**
+ * Creates {@link DocumentBuilder} instance.
+ * The default implementation is configured to prevent
+ * possible XML attacks (see {@link DefaultSafeXmlParserFactory}).
+ * But you can use {@link XmlProcessorCreator#setXmlParserFactory} to set your specific
+ * factory for creating xml parsers.
+ *
+ * @param namespaceAware specifies whether the parser should be namespace aware
+ * @param ignoringComments specifies whether the parser should ignore comments
+ *
+ * @return safe {@link DocumentBuilder} instance
+ */
+ public static DocumentBuilder createSafeDocumentBuilder(boolean namespaceAware, boolean ignoringComments) {
+ return xmlParserFactory.createDocumentBuilderInstance(namespaceAware, ignoringComments);
+ }
+
+
+ /**
+ * Creates {@link XMLReader} instance.
+ * The default implementation is configured to prevent
+ * possible XML attacks (see {@link DefaultSafeXmlParserFactory}).
+ * But you can use {@link XmlProcessorCreator#setXmlParserFactory} to set your specific
+ * factory for creating xml parsers.
+ *
+ * @param namespaceAware specifies whether the parser should be namespace aware
+ * @param validating specifies whether the parser should validate documents as they are parsed
+ *
+ * @return safe {@link XMLReader} instance
+ */
+ public static XMLReader createSafeXMLReader(boolean namespaceAware, boolean validating) {
+ return xmlParserFactory.createXMLReaderInstance(namespaceAware, validating);
+ }
+}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/utils/XmlUtils.java b/kernel/src/main/java/com/itextpdf/kernel/utils/XmlUtils.java
index 00d49a6289..9a4ae16d5e 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/utils/XmlUtils.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/utils/XmlUtils.java
@@ -42,14 +42,11 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.kernel.utils;
-import org.w3c.dom.Document;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
@@ -57,10 +54,8 @@ This file is part of the iText (R) project.
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.StringReader;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
final class XmlUtils {
public static void writeXmlDocToStream(Document xmlReport, OutputStream stream) throws TransformerException {
@@ -78,13 +73,7 @@ public static void writeXmlDocToStream(Document xmlReport, OutputStream stream)
}
public static boolean compareXmls(InputStream xml1, InputStream xml2) throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- dbf.setCoalescing(true);
- dbf.setIgnoringElementContentWhitespace(true);
- dbf.setIgnoringComments(true);
- DocumentBuilder db = dbf.newDocumentBuilder();
- db.setEntityResolver(new SafeEmptyEntityResolver());
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(true, true);
Document doc1 = db.parse(xml1);
doc1.normalizeDocument();
@@ -96,14 +85,7 @@ public static boolean compareXmls(InputStream xml1, InputStream xml2) throws Par
}
public static Document initNewXmlDocument() throws ParserConfigurationException {
- return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ DocumentBuilder db = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
+ return db.newDocument();
}
-
- // Prevents XXE attacks
- private static class SafeEmptyEntityResolver implements EntityResolver {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- }
-
}
diff --git a/kernel/src/main/java/com/itextpdf/kernel/xmp/impl/XMPMetaParser.java b/kernel/src/main/java/com/itextpdf/kernel/xmp/impl/XMPMetaParser.java
index b3b287a727..6714300b30 100644
--- a/kernel/src/main/java/com/itextpdf/kernel/xmp/impl/XMPMetaParser.java
+++ b/kernel/src/main/java/com/itextpdf/kernel/xmp/impl/XMPMetaParser.java
@@ -30,6 +30,7 @@
package com.itextpdf.kernel.xmp.impl;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
import com.itextpdf.kernel.xmp.XMPConst;
import com.itextpdf.kernel.xmp.XMPError;
import com.itextpdf.kernel.xmp.XMPException;
@@ -42,17 +43,11 @@
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
-
-import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
-import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -68,8 +63,6 @@ public class XMPMetaParser
{
/** */
private static final Object XMP_RDF = new Object();
- /** the DOM Parser Factory, options are set */
- private static DocumentBuilderFactory factory = createDocumentBuilderFactory();
/**
* Hidden constructor, initialises the SAX parser handler.
@@ -286,26 +279,14 @@ private static Document parseXmlFromString(String input, ParseOptions options)
* @return Returns an XML DOM-Document.
* @throws XMPException Wraps parsing and I/O-exceptions into an XMPException.
*/
- private static Document parseInputSource(InputSource source) throws XMPException
- {
- try
- {
- DocumentBuilder builder = factory.newDocumentBuilder();
+ private static Document parseInputSource(InputSource source) throws XMPException {
+ try {
+ DocumentBuilder builder = XmlProcessorCreator.createSafeDocumentBuilder(true, true);
builder.setErrorHandler(null);
- builder.setEntityResolver(new SafeEmptyEntityResolver());
return builder.parse(source);
- }
- catch (SAXException e)
- {
- throw new XMPException("XML parsing failure", XMPError.BADXML, e);
- }
- catch (ParserConfigurationException e)
- {
- throw new XMPException("XML Parser not correctly configured",
- XMPError.UNKNOWN, e);
- }
- catch (IOException e)
- {
+ } catch (SAXException e) {
+ throw new XMPException(e.getMessage(), XMPError.BADXML, e);
+ } catch (IOException e) {
throw new XMPException("Error reading the XML-file", XMPError.BADSTREAM, e);
}
}
@@ -406,36 +387,4 @@ else if (!xmpmetaRequired &&
return null;
// is extracted here in the C++ Toolkit
}
-
-
- /**
- * @return Creates, configures and returnes the document builder factory for
- * the Metadata Parser.
- */
- private static DocumentBuilderFactory createDocumentBuilderFactory()
- {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setIgnoringComments(true);
-
- try
- {
- // honor System parsing limits, e.g.
- // System.setProperty("entityExpansionLimit", "10");
- factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
- }
- catch (Exception e)
- {
- // Ignore IllegalArgumentException and ParserConfigurationException
- // in case the configured XML-Parser does not implement the feature.
- }
- return factory;
- }
-
- // Prevents XXE attacks
- private static class SafeEmptyEntityResolver implements EntityResolver {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- }
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/VersionTest.java b/kernel/src/test/java/com/itextpdf/kernel/VersionTest.java
index f25658db43..6a120b2c84 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/VersionTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/VersionTest.java
@@ -26,17 +26,12 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class VersionTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void parseCurrentVersionTest() {
Version instance = Version.getInstance();
@@ -71,20 +66,20 @@ public void parseCustomCorrectVersionTest() {
@Test
public void parseVersionIncorrectMajorTest() {
- junitExpectedException.expect(LicenseVersionException.class);
- junitExpectedException.expectMessage(LicenseVersionException.MAJOR_VERSION_IS_NOT_NUMERIC);
-
// the line below is expected to produce an exception
- String[] parseResults = Version.parseVersionString("a.9.11");
+ Exception e = Assert.assertThrows(LicenseVersionException.class,
+ () -> Version.parseVersionString("a.9.11")
+ );
+ Assert.assertEquals(LicenseVersionException.MAJOR_VERSION_IS_NOT_NUMERIC, e.getMessage());
}
@Test
public void parseVersionIncorrectMinorTest() {
- junitExpectedException.expect(LicenseVersionException.class);
- junitExpectedException.expectMessage(LicenseVersionException.MINOR_VERSION_IS_NOT_NUMERIC);
-
// the line below is expected to produce an exception
- Version.parseVersionString("1.a.11");
+ Exception e = Assert.assertThrows(LicenseVersionException.class,
+ () -> Version.parseVersionString("1.a.11")
+ );
+ Assert.assertEquals(LicenseVersionException.MINOR_VERSION_IS_NOT_NUMERIC, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/colors/ColorTest.java b/kernel/src/test/java/com/itextpdf/kernel/colors/ColorTest.java
index 9944805eca..23ef6a8f65 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/colors/ColorTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/colors/ColorTest.java
@@ -53,18 +53,14 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.colorspace.PdfSpecialCs;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
+
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class ColorTest extends ExtendedITextTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
private static final float EPS = 1e-4f;
@Test
@@ -85,13 +81,13 @@ public void convertRgbToCmykTest() {
@Test
public void setColorValueIncorrectComponentsNumberTest() {
- expectedException.expect(PdfException.class);
- expectedException.expectMessage(PdfException.IncorrectNumberOfComponents);
-
float[] colorValues = new float[]{0.0f, 0.5f, 0.1f};
Color color = Color.makeColor(PdfColorSpace.makeColorSpace(PdfName.DeviceRGB), colorValues);
- color.setColorValue(new float[]{0.1f, 0.2f});
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> color.setColorValue(new float[]{0.1f, 0.2f})
+ );
+ Assert.assertEquals(PdfException.IncorrectNumberOfComponents, e.getMessage());
}
@Test
@@ -162,11 +158,10 @@ public void notEqualsDifferentClassesTest() {
@Test
public void nullColorSpaceTest() {
- expectedException.expect(PdfException.class);
- expectedException.expectMessage("Unknown color space.");
-
float[] colorValues = new float[]{0.0f, 0.5f, 0.1f};
- Color color = Color.makeColor(null, colorValues);
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> Color.makeColor(null, colorValues));
+ Assert.assertEquals("Unknown color space.", e.getMessage());
}
@Test
@@ -209,10 +204,8 @@ public void makeDeviceCmykTest() {
@Test
public void unknownDeviceCsTest() {
- expectedException.expect(PdfException.class);
- expectedException.expectMessage("Unknown color space.");
-
- Color color = Color.makeColor(new CustomDeviceCs(null));
+ Exception e = Assert.assertThrows(PdfException.class, () -> Color.makeColor(new CustomDeviceCs(null)));
+ Assert.assertEquals("Unknown color space.", e.getMessage());
}
@Test
@@ -310,10 +303,10 @@ public void makeLabTest() {
@Test
public void unknownCieBasedCsTest() {
- expectedException.expect(PdfException.class);
- expectedException.expectMessage("Unknown color space.");
-
- Color color = Color.makeColor(new CustomPdfCieBasedCs(new PdfArray()));
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> Color.makeColor(new CustomPdfCieBasedCs(new PdfArray()))
+ );
+ Assert.assertEquals("Unknown color space.", e.getMessage());
}
@Test
@@ -380,10 +373,10 @@ public void makeIndexedTest() {
@Test
public void unknownSpecialCsTest() {
- expectedException.expect(PdfException.class);
- expectedException.expectMessage("Unknown color space.");
-
- Color color = Color.makeColor(new CustomPdfSpecialCs(new PdfArray()));
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> Color.makeColor(new CustomPdfSpecialCs(new PdfArray()))
+ );
+ Assert.assertEquals("Unknown color space.", e.getMessage());
}
private static class CustomDeviceCs extends PdfDeviceCs {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/counter/DataHandlerCounterTest.java b/kernel/src/test/java/com/itextpdf/kernel/counter/DataHandlerCounterTest.java
index b07b0c2366..af74cc5db7 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/counter/DataHandlerCounterTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/counter/DataHandlerCounterTest.java
@@ -40,17 +40,12 @@ This file is part of the iText (R) project.
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class DataHandlerCounterTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void disableHooksTest() throws InterruptedException {
final int betweenChecksSleepTime = 500;
@@ -84,9 +79,8 @@ public void onEventAfterDisableTest() throws InterruptedException {
counter.close();
- junitExpectedException.expect(IllegalStateException.class);
- junitExpectedException.expectMessage(PdfException.DataHandlerCounterHasBeenDisabled);
- counter.onEvent(testEvent, null);
+ Exception e = Assert.assertThrows(IllegalStateException.class, () -> counter.onEvent(testEvent, null));
+ Assert.assertEquals(PdfException.DataHandlerCounterHasBeenDisabled, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfEncryptionTest.java b/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfEncryptionTest.java
index 3b7586f937..506eb14692 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfEncryptionTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfEncryptionTest.java
@@ -71,13 +71,12 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.FileInputStream;
import java.io.IOException;
@@ -127,9 +126,6 @@ public class PdfEncryptionTest extends ExtendedITextTest {
*/
public static byte[] OWNER = "World".getBytes(StandardCharsets.ISO_8859_1);
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
private PrivateKey privateKey;
@BeforeClass
@@ -253,95 +249,98 @@ public void encryptWithCertificateAes256NoCompression() throws IOException, Inte
@Test
public void openEncryptedDocWithoutPassword() throws IOException {
- junitExpectedException.expect(BadPasswordException.class);
- junitExpectedException.expectMessage(BadPasswordException.BadUserPassword);
-
- PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf"));
- doc.close();
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf")) {
+ Exception e = Assert.assertThrows(BadPasswordException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(BadPasswordException.BadUserPassword, e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithWrongPassword() throws IOException {
- junitExpectedException.expect(BadPasswordException.class);
- junitExpectedException.expectMessage(BadPasswordException.BadUserPassword);
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf",
+ new ReaderProperties().setPassword("wrong_password".getBytes(StandardCharsets.ISO_8859_1)))) {
- PdfReader reader = new PdfReader(sourceFolder + "encryptedWithPasswordStandard40.pdf",
- new ReaderProperties().setPassword("wrong_password".getBytes(StandardCharsets.ISO_8859_1)));
- PdfDocument doc = new PdfDocument(reader);
- doc.close();
+ Exception e = Assert.assertThrows(BadPasswordException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(BadPasswordException.BadUserPassword, e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithoutCertificate() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.CertificateIsNotProvidedDocumentIsEncryptedWithPublicKeyCertificate);
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf")) {
- PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf"));
- doc.close();
+ Exception e = Assert.assertThrows(PdfException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(PdfException.CertificateIsNotProvidedDocumentIsEncryptedWithPublicKeyCertificate,
+ e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithoutPrivateKey() throws IOException, CertificateException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.BadCertificateAndKey);
-
- PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
new ReaderProperties()
.setPublicKeySecurityParams(
getPublicCertificate(sourceFolder + "wrong.cer"),
null,
"BC",
- null));
- PdfDocument doc = new PdfDocument(reader);
- doc.close();
+ null))) {
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(PdfException.BadCertificateAndKey, e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithWrongCertificate() throws IOException, GeneralSecurityException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.BadCertificateAndKey);
-
- PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
new ReaderProperties()
.setPublicKeySecurityParams(
getPublicCertificate(sourceFolder + "wrong.cer"),
getPrivateKey(),
"BC",
- null));
- PdfDocument doc = new PdfDocument(reader);
- doc.close();
+ null))) {
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(PdfException.BadCertificateAndKey, e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithWrongPrivateKey() throws IOException, GeneralSecurityException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.PdfDecryption);
-
- PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
new ReaderProperties()
.setPublicKeySecurityParams(
getPublicCertificate(CERT),
CryptoUtil.readPrivateKeyFromPKCS12KeyStore(new FileInputStream(sourceFolder + "wrong.p12"), "demo", "password".toCharArray()),
"BC",
- null));
- PdfDocument doc = new PdfDocument(reader);
- doc.close();
+ null))) {
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(PdfException.PdfDecryption, e.getMessage());
+ }
}
@Test
public void openEncryptedDocWithWrongCertificateAndPrivateKey() throws IOException, GeneralSecurityException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.BadCertificateAndKey);
-
- PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
+ try (PdfReader reader = new PdfReader(sourceFolder + "encryptedWithCertificateAes128.pdf",
new ReaderProperties()
.setPublicKeySecurityParams(
getPublicCertificate(sourceFolder + "wrong.cer"),
CryptoUtil.readPrivateKeyFromPKCS12KeyStore(new FileInputStream(sourceFolder + "wrong.p12"), "demo", "password".toCharArray()),
"BC",
- null));
- PdfDocument doc = new PdfDocument(reader);
- doc.close();
+ null))) {
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(PdfException.BadCertificateAndKey, e.getMessage());
+ }
}
@Test
@@ -389,12 +388,14 @@ public void openDocNoUserPassword() throws IOException {
@Test
public void stampDocNoUserPassword() throws IOException {
- junitExpectedException.expect(BadPasswordException.class);
- junitExpectedException.expectMessage(BadPasswordException.PdfReaderNotOpenedWithOwnerPassword);
-
String fileName = "stampedNoPassword.pdf";
- PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + "noUserPassword.pdf"), new PdfWriter(destinationFolder + fileName));
- document.close();
+
+ try (PdfReader reader = new PdfReader(sourceFolder + "noUserPassword.pdf");
+ PdfWriter writer = new PdfWriter(destinationFolder + fileName)) {
+
+ Exception e = Assert.assertThrows(BadPasswordException.class, () -> new PdfDocument(reader, writer));
+ Assert.assertEquals(BadPasswordException.PdfReaderNotOpenedWithOwnerPassword, e.getMessage());
+ }
}
@Test
@@ -421,9 +422,9 @@ public void encryptWithPasswordAes128EmbeddedFilesOnly() throws IOException {
document.close();
- //NOTE: Specific crypto filters for EFF StmF and StrF are not supported at the moment. iText don't distinguish objects based on their semantic role
- // because of this we can't read streams correctly and corrupt such documents on stamping.
- boolean ERROR_IS_EXPECTED = true;
+ //TODO DEVSIX-5355 Specific crypto filters for EFF StmF and StrF are not supported at the moment.
+ // However we can read embedded files only mode.
+ boolean ERROR_IS_EXPECTED = false;
checkDecryptedWithPasswordContent(destinationFolder + filename, OWNER, textContent, ERROR_IS_EXPECTED);
checkDecryptedWithPasswordContent(destinationFolder + filename, USER, textContent, ERROR_IS_EXPECTED);
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfReaderCustomFilterTest.java b/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfReaderCustomFilterTest.java
index fd64930dec..0533570e8f 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfReaderCustomFilterTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/crypto/PdfReaderCustomFilterTest.java
@@ -30,25 +30,20 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import java.io.IOException;
-import org.junit.Rule;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfReaderCustomFilterTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/crypto/PdfReaderCustomFilterTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void encryptedDocumentCustomFilterStandartTest() throws IOException {
- junitExpectedException.expect(UnsupportedSecurityHandlerException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.
- format(UnsupportedSecurityHandlerException.UnsupportedSecurityHandler, "/Standart"));
-
- PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder + "customSecurityHandler.pdf"));
- doc.close();
+ try (PdfReader reader = new PdfReader(sourceFolder + "customSecurityHandler.pdf")) {
+ Exception e = Assert.assertThrows(UnsupportedSecurityHandlerException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(MessageFormatUtil.format(UnsupportedSecurityHandlerException.UnsupportedSecurityHandler,
+ "/Standart"), e.getMessage());
+ }
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontFactoryTest.java b/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontFactoryTest.java
index c1f0a642de..7674efac9c 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontFactoryTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontFactoryTest.java
@@ -38,26 +38,22 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfFontFactoryTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/font/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void standardFontForceEmbeddedTest() throws IOException {
Type1Font fontProgram = (Type1Font) FontProgramFactory.createFont(StandardFonts.HELVETICA);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.CannotEmbedStandardFont);
- PdfFontFactory.createFont(fontProgram, PdfEncodings.UTF8, EmbeddingStrategy.FORCE_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.UTF8, EmbeddingStrategy.FORCE_EMBEDDED)
+ );
+ Assert.assertEquals(PdfException.CannotEmbedStandardFont, e.getMessage());
}
@Test
@@ -174,9 +170,11 @@ public void trueTypeFontProgramUTF8AllowEmbeddingEncodingForceNotEmbeddedTest()
public void trueTypeFontProgramUTF8NotAllowEmbeddingEncodingForceEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(false);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"));
- PdfFontFactory.createFont(fontProgram, PdfEncodings.UTF8, EmbeddingStrategy.FORCE_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.UTF8, EmbeddingStrategy.FORCE_EMBEDDED)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"),
+ e.getMessage());
}
@Test
@@ -243,49 +241,54 @@ public void trueTypeFontProgramIdentityHAllowEmbeddingEncodingPreferNotEmbeddedT
public void trueTypeFontProgramIdentityHAllowEmbeddingEncodingForceNotEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(true);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.CannotCreateType0FontWithTrueTypeFontProgramWithoutEmbedding);
- PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_NOT_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_NOT_EMBEDDED)
+ );
+ Assert.assertEquals(PdfException.CannotCreateType0FontWithTrueTypeFontProgramWithoutEmbedding, e.getMessage());
}
@Test
public void trueTypeFontProgramIdentityHNotAllowEmbeddingEncodingForceEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(false);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"));
- PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_EMBEDDED)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions,
+ "CustomNameCustomStyle"), e.getMessage());
}
@Test
public void trueTypeFontProgramIdentityHNotAllowEmbeddingEncodingPreferEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(false);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"));
- PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_EMBEDDED)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions,
+ "CustomNameCustomStyle"), e.getMessage());
}
@Test
public void trueTypeFontProgramIdentityHNotAllowEmbeddingEncodingPreferNotEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(false);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"));
- PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_NOT_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.PREFER_NOT_EMBEDDED)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions,
+ "CustomNameCustomStyle"), e.getMessage());
}
@Test
public void trueTypeFontProgramIdentityHNotAllowEmbeddingEncodingForceNotEmbeddedTest() {
TrueTypeFont fontProgram = new CustomTrueTypeFontProgram(false);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.CannotBeEmbeddedDueToLicensingRestrictions, "CustomNameCustomStyle"));
- PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_NOT_EMBEDDED);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, EmbeddingStrategy.FORCE_NOT_EMBEDDED)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.CannotBeEmbeddedDueToLicensingRestrictions,
+ "CustomNameCustomStyle"), e.getMessage());
}
@Test
@@ -303,18 +306,16 @@ public void standardFontCachedWithoutDocumentTest() throws IOException {
public void createFontFromNullDictionaryTest() {
PdfDictionary dictionary = null;
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.CannotCreateFontFromNullFontDictionary);
- PdfFontFactory.createFont(dictionary);
+ Exception e = Assert.assertThrows(PdfException.class, () -> PdfFontFactory.createFont(dictionary));
+ Assert.assertEquals(PdfException.CannotCreateFontFromNullFontDictionary, e.getMessage());
}
@Test
public void createFontFromEmptyDictionaryTest() {
PdfDictionary dictionary = new PdfDictionary();
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DictionaryDoesntHaveSupportedFontData);
- PdfFontFactory.createFont(dictionary);
+ Exception e = Assert.assertThrows(PdfException.class, () -> PdfFontFactory.createFont(dictionary));
+ Assert.assertEquals(PdfException.DictionaryDoesntHaveSupportedFontData, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontUnitTest.java b/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontUnitTest.java
index 277a655805..279c1f0a8a 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontUnitTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/font/PdfFontUnitTest.java
@@ -60,10 +60,8 @@ This file is part of the iText (R) project.
import java.util.List;
import java.util.regex.Pattern;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfFontUnitTest extends ExtendedITextTest {
@@ -204,9 +202,6 @@ public TestFontMetrics() {
}
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void constructorWithoutParamsTest() {
TestFont font = new TestFont();
@@ -569,9 +564,10 @@ public void updateEmbeddedSubsetPrefixTest() {
public void getEmptyPdfStreamTest() {
TestFont font = new TestFont();
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.FontEmbeddingIssue);
- font.getPdfFontStream(null, null);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> font.getPdfFontStream(null, null)
+ );
+ Assert.assertEquals(PdfException.FontEmbeddingIssue, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java
index 5ac485f774..532080f760 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java
@@ -35,19 +35,14 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfType0FontTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/font/PdfType0FontTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void trueTypeFontAndCmapConstructorTest() throws IOException {
TrueTypeFont ttf = new TrueTypeFont(sourceFolder + "NotoSerif-Regular_v1.7.ttf");
@@ -68,11 +63,12 @@ public void trueTypeFontAndCmapConstructorTest() throws IOException {
@Test
public void unsupportedCmapTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.OnlyIdentityCMapsSupportsWithTrueType);
-
TrueTypeFont ttf = new TrueTypeFont(sourceFolder + "NotoSerif-Regular_v1.7.ttf");
- PdfType0Font type0Font = new PdfType0Font(ttf, PdfEncodings.WINANSI);
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfType0Font(ttf, PdfEncodings.WINANSI)
+ );
+ Assert.assertEquals(PdfException.OnlyIdentityCMapsSupportsWithTrueType, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType3FontTest.java b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType3FontTest.java
index 27d15c0c19..5cd0a64236 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/font/PdfType3FontTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/font/PdfType3FontTest.java
@@ -37,19 +37,15 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.UnitTest;
+
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfType3FontTest extends ExtendedITextTest {
private static final float EPS = 1e-4f;
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.TYPE3_FONT_INITIALIZATION_ISSUE)})
public void addDifferentGlyphsInConstructorTest() {
@@ -176,8 +172,6 @@ protected PdfDocument getDocument() {
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.TYPE3_FONT_INITIALIZATION_ISSUE)})
public void flushExceptionTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.NoGlyphsDefinedForType3Font);
PdfDictionary dictionary = new PdfDictionary();
dictionary.put(PdfName.FontMatrix, new PdfArray());
PdfDictionary charProcs = new PdfDictionary();
@@ -185,7 +179,10 @@ public void flushExceptionTest() {
dictionary.put(PdfName.Widths, new PdfArray());
PdfType3Font type3Font = new DisableEnsureUnderlyingObjectHasIndirectReference(dictionary);
- type3Font.flush();
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> type3Font.flush()
+ );
+ Assert.assertEquals(PdfException.NoGlyphsDefinedForType3Font, e.getMessage());
}
@Test
@@ -248,31 +245,30 @@ public void noDifferenceTest() {
}
@Test
- @LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.TYPE3_FONT_INITIALIZATION_ISSUE)})
public void missingFontMatrixTest() {
PdfDictionary dictionary = new PdfDictionary();
dictionary.put(PdfName.Widths, new PdfArray());
dictionary.put(PdfName.ToUnicode, PdfName.IdentityH);
dictionary.put(PdfName.Encoding, new PdfName("zapfdingbatsencoding"));
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.MissingRequiredFieldInFontDictionary, PdfName.FontMatrix));
- new PdfType3Font(dictionary);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfType3Font(dictionary)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.MissingRequiredFieldInFontDictionary, PdfName.FontMatrix), e.getMessage());
}
@Test
- @LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.TYPE3_FONT_INITIALIZATION_ISSUE)})
public void missingWidthsTest() {
PdfDictionary dictionary = new PdfDictionary();
dictionary.put(PdfName.FontMatrix, new PdfArray());
dictionary.put(PdfName.ToUnicode, PdfName.IdentityH);
dictionary.put(PdfName.Encoding, new PdfName("zapfdingbatsencoding"));
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.MissingRequiredFieldInFontDictionary, PdfName.Widths));
- new PdfType3Font(dictionary);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfType3Font(dictionary)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(
+ PdfException.MissingRequiredFieldInFontDictionary, PdfName.Widths), e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest.java
new file mode 100644
index 0000000000..ab5ed5cf59
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest.java
@@ -0,0 +1,170 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.kernel.pdf;
+
+import com.itextpdf.kernel.geom.Rectangle;
+import com.itextpdf.kernel.pdf.annot.PdfFileAttachmentAnnotation;
+import com.itextpdf.kernel.pdf.filespec.PdfFileSpec;
+import com.itextpdf.kernel.utils.CompareTool;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.IntegrationTest;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+
+@Category(IntegrationTest.class)
+public class EncryptedEmbeddedStreamsHandlerTest extends ExtendedITextTest {
+
+ public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/";
+ public static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/";
+
+ @BeforeClass
+ public static void beforeClass() {
+ createDestinationFolder(destinationFolder);
+ }
+
+ @Test
+ public void noReaderStandardEncryptionAddFileAttachment() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "noReaderStandardEncryptionAddFileAttachment.pdf";
+ String cmpFileName = sourceFolder + "cmp_noReaderStandardEncryptionAddFileAttachment.pdf";
+
+ PdfDocument pdfDocument = createEncryptedDocument(EncryptionConstants.STANDARD_ENCRYPTION_128, outFileName);
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.addFileAttachment("file.txt", fs);
+
+ pdfDocument.addNewPage();
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff", "password".getBytes(), "password".getBytes()));
+ }
+
+ @Test
+ public void noReaderAesEncryptionAddFileAttachment() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "noReaderAesEncryptionAddFileAttachment.pdf";
+ String cmpFileName = sourceFolder + "cmp_noReaderAesEncryptionAddFileAttachment.pdf";
+
+ PdfDocument pdfDocument = createEncryptedDocument(EncryptionConstants.ENCRYPTION_AES_128, outFileName);
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.addFileAttachment("file.txt", fs);
+
+ pdfDocument.addNewPage();
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff", "password".getBytes(), "password".getBytes()));
+ }
+
+ @Test
+ public void withReaderStandardEncryptionAddFileAttachment() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "withReaderStandardEncryptionAddFileAttachment.pdf";
+ String cmpFileName = sourceFolder + "cmp_withReaderStandardEncryptionAddFileAttachment.pdf";
+
+ PdfReader reader = new PdfReader(sourceFolder + "pdfWithFileAttachments.pdf", new ReaderProperties().setPassword("password".getBytes()));
+ // Setting compression level to zero doesn't affect the encryption at any level.
+ // We do it to simplify observation of the resultant PDF.
+ PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(outFileName).setCompressionLevel(0));
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.addFileAttachment("file.txt", fs);
+
+ pdfDocument.addNewPage();
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
+ }
+
+ @Test
+ public void noReaderStandardEncryptionAddAnnotation() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "noReaderStandardEncryptionAddAnnotation.pdf";
+ String cmpFileName = sourceFolder + "cmp_noReaderStandardEncryptionAddAnnotation.pdf";
+
+ PdfDocument pdfDocument = createEncryptedDocument(EncryptionConstants.STANDARD_ENCRYPTION_128, outFileName);
+ pdfDocument.addNewPage();
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.getPage(1).addAnnotation(new PdfFileAttachmentAnnotation(new Rectangle(100, 100), fs));
+
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff", "password".getBytes(), "password".getBytes()));
+ }
+
+ @Test
+ public void withReaderStandardEncryptionAddAnnotation() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "withReaderStandardEncryptionAddAnnotation.pdf";
+ String cmpFileName = sourceFolder + "cmp_withReaderStandardEncryptionAddAnnotation.pdf";
+
+ PdfReader reader = new PdfReader(sourceFolder + "pdfWithFileAttachmentAnnotations.pdf", new ReaderProperties().setPassword("password".getBytes()));
+ // Setting compression level to zero doesn't affect the encryption at any level.
+ // We do it to simplify observation of the resultant PDF.
+ PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(outFileName).setCompressionLevel(0));
+ pdfDocument.addNewPage();
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.getPage(1).addAnnotation(new PdfFileAttachmentAnnotation(new Rectangle(100, 100), fs));
+
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
+ }
+
+ @Test
+ public void readerWithoutEncryptionWriterStandardEncryption() throws IOException, InterruptedException {
+ String outFileName = destinationFolder + "readerWithoutEncryptionWriterStandardEncryption.pdf";
+ String cmpFileName = sourceFolder + "cmp_readerWithoutEncryptionWriterStandardEncryption.pdf";
+
+ PdfReader reader = new PdfReader(sourceFolder + "pdfWithUnencryptedAttachmentAnnotations.pdf");
+ PdfDocument pdfDocument = createEncryptedDocument(reader, EncryptionConstants.STANDARD_ENCRYPTION_128, outFileName);
+ PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(
+ pdfDocument, "file".getBytes(), "description", "file.txt", null, null, null);
+ pdfDocument.addFileAttachment("new attachment", fs);
+
+ pdfDocument.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff", "password".getBytes(), "password".getBytes()));
+ }
+
+ private PdfDocument createEncryptedDocument(int encryptionAlgorithm, String outFileName) throws IOException {
+ PdfWriter writer = new PdfWriter(outFileName,
+ new WriterProperties().setStandardEncryption(
+ "password".getBytes(), "password".getBytes(), 0, encryptionAlgorithm | EncryptionConstants.EMBEDDED_FILES_ONLY));
+ // Setting compression level to zero doesn't affect the encryption at any level.
+ // We do it to simplify observation of the resultant PDF.
+ writer.setCompressionLevel(0);
+ return new PdfDocument(writer);
+ }
+
+ private PdfDocument createEncryptedDocument(PdfReader reader, int encryptionAlgorithm, String outFileName) throws IOException {
+ PdfWriter writer = new PdfWriter(outFileName,
+ new WriterProperties().setStandardEncryption(
+ "password".getBytes(), "password".getBytes(), 0, encryptionAlgorithm | EncryptionConstants.EMBEDDED_FILES_ONLY));
+ // Setting compression level to zero doesn't affect the encryption at any level.
+ // We do it to simplify observation of the resultant PDF.
+ writer.setCompressionLevel(0);
+ return new PdfDocument(reader, writer);
+ }
+}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/MemoryLimitsAwareOutputStreamTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/MemoryLimitsAwareOutputStreamTest.java
index d218e8b524..e59bdf06ad 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/MemoryLimitsAwareOutputStreamTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/MemoryLimitsAwareOutputStreamTest.java
@@ -45,20 +45,14 @@ This file is part of the iText (R) project.
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class MemoryLimitsAwareOutputStreamTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void testMaxSize() {
- junitExpectedException.expect(MemoryLimitsAwareException.class);
byte[] bigArray = new byte[70];
byte[] smallArray = new byte[31];
@@ -68,28 +62,27 @@ public void testMaxSize() {
Assert.assertEquals(100, stream.getMaxStreamSize());
stream.write(bigArray, 0, bigArray.length);
- Assert.assertEquals(bigArray.length, stream.size());
- stream.write(smallArray, 0, smallArray.length);
+ Assert.assertEquals(bigArray.length, stream.size());
+ Assert.assertThrows(MemoryLimitsAwareException.class, () -> stream.write(smallArray, 0, smallArray.length));
}
@Test
public void testNegativeSize() {
- junitExpectedException.expect(MemoryLimitsAwareException.class);
byte[] zeroArray = new byte[0];
MemoryLimitsAwareOutputStream stream = new MemoryLimitsAwareOutputStream();
stream.setMaxStreamSize(-100);
- Assert.assertEquals(-100, stream.getMaxStreamSize());
- stream.write(zeroArray, 0, zeroArray.length);
+ Assert.assertEquals(-100, stream.getMaxStreamSize());
+ Assert.assertThrows(MemoryLimitsAwareException.class, () -> stream.write(zeroArray, 0, zeroArray.length));
}
@Test
public void testIncorrectLength() {
- junitExpectedException.expect(IndexOutOfBoundsException.class);
MemoryLimitsAwareOutputStream stream = new MemoryLimitsAwareOutputStream();
- stream.write(new byte[1],0, -1);
+
+ Assert.assertThrows(IndexOutOfBoundsException.class, () -> stream.write(new byte[1],0, -1));
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PageFlushingTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PageFlushingTest.java
index 173ca15833..df8df342ef 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PageFlushingTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PageFlushingTest.java
@@ -127,7 +127,7 @@ public void baseReading01() throws IOException {
int total = 817;
int flushedExpected = 0;
// link annots, line annots, actions and images: one hundred of each
- int notReadExpected = 401;
+ int notReadExpected = 402;
test("baseReading01.pdf", DocMode.READING, FlushMode.NONE, PagesOp.READ,
total, flushedExpected, notReadExpected);
@@ -137,7 +137,7 @@ public void baseReading01() throws IOException {
public void releaseDeepReading01() throws IOException {
int total = 817;
int flushedExpected = 0;
- int notReadExpected = 803;
+ int notReadExpected = 804;
test("releaseDeepReading01.pdf", DocMode.READING, FlushMode.RELEASE_DEEP, PagesOp.READ,
total, flushedExpected, notReadExpected);
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfCopyTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfCopyTest.java
index af0c61246b..16af0001f3 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfCopyTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfCopyTest.java
@@ -53,17 +53,14 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -73,9 +70,6 @@ public class PdfCopyTest extends ExtendedITextTest {
public static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/PdfCopyTest/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -381,10 +375,8 @@ public void copyDifferentRangesOfPagesWithBookmarksTest() throws IOException, In
}
@Test
- // TODO DEVSIX-577. Update cmp, remove junitExpectedException after fix
+ // TODO DEVSIX-577. Update cmp
public void copyPagesLinkAnnotationTest() throws IOException, InterruptedException {
- junitExpectedException.expect(AssertionError.class);
-
String outFileName = destinationFolder + "copyPagesLinkAnnotationTest.pdf";
String cmpFileName = sourceFolder + "cmp_copyPagesLinkAnnotationTest.pdf";
PdfDocument targetPdf = new PdfDocument(new PdfWriter(outFileName));
@@ -397,7 +389,7 @@ public void copyPagesLinkAnnotationTest() throws IOException, InterruptedExcepti
linkAnotPdf.copyPagesTo(1, 2, targetPdf);
List annotations = getPdfAnnotations(targetPdf);
- Assert.assertEquals("The number of merged annotations are not the same.", 1, annotations.size());
+ Assert.assertEquals("The number of merged annotations are not the same.", 0, annotations.size());
linkAnotPdf.close();
targetPdf.close();
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentIdTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentIdTest.java
index 9566e8ce3c..3fffcc24c1 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentIdTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentIdTest.java
@@ -58,10 +58,8 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
/**
* @author Michael Demey
@@ -71,9 +69,6 @@ public class PdfDocumentIdTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentTestID/";
public static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/PdfDocumentTestID/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -386,9 +381,8 @@ public void readPdfWithNoIdAndConservativeReadingTest() throws IOException{
try (PdfReader reader = new PdfReader(sourceFolder + "pdfWithNoId.pdf")
.setStrictnessLevel(StrictnessLevel.CONSERVATIVE)) {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(LogMessageConstant.DOCUMENT_IDS_ARE_CORRUPTED);
- new PdfDocument(reader);
+ Exception e = Assert.assertThrows(PdfException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(LogMessageConstant.DOCUMENT_IDS_ARE_CORRUPTED, e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java
index 361d2729ad..6d8d3810d8 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentTest.java
@@ -74,10 +74,8 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfDocumentTest extends ExtendedITextTest {
@@ -85,9 +83,6 @@ public class PdfDocumentTest extends ExtendedITextTest {
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentTest/";
public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/PdfDocumentTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(DESTINATION_FOLDER);
@@ -550,9 +545,10 @@ public void openDocumentWithInvalidCatalogVersionAndConservativeStrictnessReadin
try (PdfReader reader = new PdfReader(SOURCE_FOLDER + "sample-with-invalid-catalog-version.pdf")
.setStrictnessLevel(StrictnessLevel.CONSERVATIVE)) {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(LogMessageConstant.DOCUMENT_VERSION_IN_CATALOG_CORRUPTED);
- new PdfDocument(reader);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(LogMessageConstant.DOCUMENT_VERSION_IN_CATALOG_CORRUPTED, e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentUnitTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentUnitTest.java
index cf2a016ae1..d5c89af12c 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentUnitTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfDocumentUnitTest.java
@@ -46,6 +46,7 @@ This file is part of the iText (R) project.
import com.itextpdf.io.LogMessageConstant;
import com.itextpdf.io.font.AdobeGlyphList;
import com.itextpdf.io.source.ByteArrayOutputStream;
+import com.itextpdf.kernel.PdfException;
import com.itextpdf.kernel.font.PdfType3Font;
import com.itextpdf.kernel.pdf.layer.PdfLayer;
import com.itextpdf.kernel.pdf.layer.PdfOCProperties;
@@ -62,15 +63,12 @@ This file is part of the iText (R) project.
import java.util.List;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfDocumentUnitTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
+ public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentUnitTest/";
@Test
@LogMessages(messages = {
@@ -235,6 +233,94 @@ public void copyPagesFlushedResources() throws IOException {
}
}
+ @Test
+ public void pdfDocumentInstanceNoWriterInfoAndConformanceLevelInitialization() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "pdfWithMetadata.pdf"));
+
+ Assert.assertNull(pdfDocument.info);
+ Assert.assertNull(pdfDocument.reader.pdfAConformanceLevel);
+
+ pdfDocument.close();
+
+ Assert.assertNull(pdfDocument.info);
+ Assert.assertNull(pdfDocument.reader.pdfAConformanceLevel);
+ }
+
+ @Test
+ public void pdfDocumentInstanceWriterInfoAndConformanceLevelInitialization() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(
+ new PdfReader(sourceFolder + "pdfWithMetadata.pdf"), new PdfWriter(new ByteArrayOutputStream()));
+
+ Assert.assertNotNull(pdfDocument.info);
+ Assert.assertNull(pdfDocument.reader.pdfAConformanceLevel);
+
+ pdfDocument.close();
+
+ Assert.assertNotNull(pdfDocument.info);
+ Assert.assertNull(pdfDocument.reader.pdfAConformanceLevel);
+ }
+
+ @Test
+ public void extendedPdfDocumentNoWriterInfoAndConformanceLevelInitialization() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "pdfWithMetadata.pdf")) {
+ // This class instance extends pdfDocument
+ };
+
+ // TODO DEVSIX-5292 These fields shouldn't be initialized during the document's opening
+ Assert.assertNotNull(pdfDocument.info);
+ Assert.assertNotNull(pdfDocument.reader.pdfAConformanceLevel);
+
+ pdfDocument.close();
+
+ Assert.assertNotNull(pdfDocument.info);
+ Assert.assertNotNull(pdfDocument.reader.pdfAConformanceLevel);
+ }
+
+ @Test
+ public void extendedPdfDocumentWriterInfoAndConformanceLevelInitialization() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(
+ new PdfReader(sourceFolder + "pdfWithMetadata.pdf"), new PdfWriter(new ByteArrayOutputStream())) {
+ // This class instance extends pdfDocument
+ };
+
+ Assert.assertNotNull(pdfDocument.info);
+ // TODO DEVSIX-5292 pdfAConformanceLevel shouldn't be initialized during the document's opening
+ Assert.assertNotNull(pdfDocument.reader.pdfAConformanceLevel);
+
+ pdfDocument.close();
+
+ Assert.assertNotNull(pdfDocument.info);
+ Assert.assertNotNull(pdfDocument.reader.pdfAConformanceLevel);
+ }
+
+ @Test
+ public void getDocumentInfoAlreadyClosedTest() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "pdfWithMetadata.pdf"));
+ pdfDocument.close();
+
+ Assert.assertThrows(PdfException.class, () -> pdfDocument.getDocumentInfo());
+ }
+
+ @Test
+ public void getDocumentInfoNotInitializedTest() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "pdfWithMetadata.pdf"));
+
+ Assert.assertNull(pdfDocument.info);
+ Assert.assertNotNull(pdfDocument.getDocumentInfo());
+
+ pdfDocument.close();
+ }
+
+ @Test
+ public void getPdfAConformanceLevelNotInitializedTest() throws IOException {
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "pdfWithMetadata.pdf"));
+
+ Assert.assertNull(pdfDocument.reader.pdfAConformanceLevel);
+ Assert.assertNotNull(pdfDocument.reader.getPdfAConformanceLevel());
+
+ pdfDocument.close();
+ }
+
private static void assertLayerNames(PdfDocument outDocument, List layerNames) {
Assert.assertNotNull(outDocument.getCatalog());
PdfOCProperties ocProperties = outDocument.getCatalog().getOCProperties(true);
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptionUnitTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptionUnitTest.java
new file mode 100644
index 0000000000..3b0916bd35
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptionUnitTest.java
@@ -0,0 +1,97 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.kernel.pdf;
+
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.UnitTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(UnitTest.class)
+public class PdfEncryptionUnitTest extends ExtendedITextTest {
+ @Test
+ public void readEncryptEmbeddedFilesOnlyFromPdfDocumentCorrectEntryTest() {
+ PdfDictionary cryptDictionary = new PdfDictionary();
+ cryptDictionary.put(PdfName.EFF, PdfName.StdCF);
+ cryptDictionary.put(PdfName.StmF, PdfName.Identity);
+ cryptDictionary.put(PdfName.StrF, PdfName.Identity);
+ PdfDictionary cfDictionary = new PdfDictionary();
+ cfDictionary.put(PdfName.StdCF, new PdfDictionary());
+ cryptDictionary.put(PdfName.CF, cfDictionary);
+
+ Assert.assertTrue(PdfEncryption.readEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary));
+ }
+
+ @Test
+ public void readEncryptEmbeddedFilesOnlyFromPdfDocumentIncorrectEffTest() {
+ PdfDictionary cryptDictionary = new PdfDictionary();
+ cryptDictionary.put(PdfName.EFF, PdfName.Identity);
+ cryptDictionary.put(PdfName.StmF, PdfName.Identity);
+ cryptDictionary.put(PdfName.StrF, PdfName.Identity);
+ PdfDictionary cfDictionary = new PdfDictionary();
+ cfDictionary.put(PdfName.StdCF, new PdfDictionary());
+ cryptDictionary.put(PdfName.CF, cfDictionary);
+
+ Assert.assertFalse(PdfEncryption.readEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary));
+ }
+
+ @Test
+ public void readEncryptEmbeddedFilesOnlyFromPdfDocumentIncorrectStmFTest() {
+ PdfDictionary cryptDictionary = new PdfDictionary();
+ cryptDictionary.put(PdfName.EFF, PdfName.StdCF);
+ cryptDictionary.put(PdfName.StmF, PdfName.StdCF);
+ cryptDictionary.put(PdfName.StrF, PdfName.Identity);
+ PdfDictionary cfDictionary = new PdfDictionary();
+ cfDictionary.put(PdfName.StdCF, new PdfDictionary());
+ cryptDictionary.put(PdfName.CF, cfDictionary);
+
+ Assert.assertFalse(PdfEncryption.readEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary));
+ }
+
+ @Test
+ public void readEncryptEmbeddedFilesOnlyFromPdfDocumentIncorrectStrFTest() {
+ PdfDictionary cryptDictionary = new PdfDictionary();
+ cryptDictionary.put(PdfName.EFF, PdfName.StdCF);
+ cryptDictionary.put(PdfName.StmF, PdfName.Identity);
+ cryptDictionary.put(PdfName.StrF, PdfName.StdCF);
+ PdfDictionary cfDictionary = new PdfDictionary();
+ cfDictionary.put(PdfName.StdCF, new PdfDictionary());
+ cryptDictionary.put(PdfName.CF, cfDictionary);
+
+ Assert.assertFalse(PdfEncryption.readEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary));
+ }
+
+ @Test
+ public void readEncryptEmbeddedFilesOnlyFromPdfDocumentIncorrectCfTest() {
+ PdfDictionary cryptDictionary = new PdfDictionary();
+ cryptDictionary.put(PdfName.EFF, PdfName.StdCF);
+ cryptDictionary.put(PdfName.StmF, PdfName.Identity);
+ cryptDictionary.put(PdfName.StrF, PdfName.Identity);
+ PdfDictionary cfDictionary = new PdfDictionary();
+ cfDictionary.put(PdfName.DefaultCryptFilter, new PdfDictionary());
+ cryptDictionary.put(PdfName.CF, cfDictionary);
+
+ Assert.assertFalse(PdfEncryption.readEmbeddedFilesOnlyFromEncryptDictionary(cryptDictionary));
+ }
+}
diff --git a/forms/src/test/java/com/itextpdf/forms/xfa/XXEVulnerabilityTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptorTest.java
similarity index 51%
rename from forms/src/test/java/com/itextpdf/forms/xfa/XXEVulnerabilityTest.java
rename to kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptorTest.java
index d9389a6de2..16252e1837 100644
--- a/forms/src/test/java/com/itextpdf/forms/xfa/XXEVulnerabilityTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfEncryptorTest.java
@@ -40,17 +40,12 @@ This file is part of the iText (R) project.
For more information, please contact iText Software Corp. at this
address: sales@itextpdf.com
*/
-package com.itextpdf.forms.xfa;
+package com.itextpdf.kernel.pdf;
-import com.itextpdf.forms.PdfAcroForm;
-import com.itextpdf.kernel.pdf.CompressionConstants;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.PdfReader;
-import com.itextpdf.kernel.pdf.PdfWriter;
-import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.IntegrationTest;
+import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -58,47 +53,36 @@ This file is part of the iText (R) project.
import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
-public class XXEVulnerabilityTest extends ExtendedITextTest {
+public class PdfEncryptorTest extends ExtendedITextTest {
- public static final String sourceFolder = "./src/test/resources/com/itextpdf/forms/xfa/XXEVulnerabilityTest/";
- public static final String destinationFolder = "./target/test/com/itextpdf/forms/xfa/XXEVulnerabilityTest/";
+ public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/PdfEncryptorTest/";
+ public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/PdfEncryptorTest/";
- @BeforeClass
- public static void initialize() {
- createDestinationFolder(destinationFolder);
- }
-
- @Test
- public void xfaExternalFileTest() throws IOException, InterruptedException {
- String inFileName = sourceFolder + "xfaExternalFile.pdf";
- String outFileName = destinationFolder + "outXfaExternalFile.pdf";
- String cmpFileName = sourceFolder + "cmp_outXfaExternalFile.pdf";
- try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inFileName),
- new PdfWriter(outFileName).setCompressionLevel(CompressionConstants.NO_COMPRESSION))) {
- PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
- // server fills out a field
- form.getField("TestField").setValue("testvalue");
- form.getXfaForm().write(pdfDoc);
- }
-
- Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder));
+ @BeforeClass
+ public static void beforeClass() {
+ createDestinationFolder(DESTINATION_FOLDER);
}
@Test
- public void xfaExternalConnectionTest() throws IOException, InterruptedException {
- String inFileName = sourceFolder + "xfaExternalConnection.pdf";
- String outFileName = destinationFolder + "outXfaExternalConnection.pdf";
- String cmpFileName = sourceFolder + "cmp_outXfaExternalConnection.pdf";
-
- try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inFileName),
- new PdfWriter(outFileName).setCompressionLevel(CompressionConstants.NO_COMPRESSION))) {
- PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
- // server fills out a field
- form.getField("TestField").setValue("testvalue");
- form.getXfaForm().write(pdfDoc);
+ public void encryptFileTest() throws IOException {
+ String outFileName = DESTINATION_FOLDER + "encryptFileTest.pdf";
+ String initialFileName = SOURCE_FOLDER + "initial.pdf";
+ PdfEncryptor encryptor = new PdfEncryptor();
+ EncryptionProperties encryptionProperties = new EncryptionProperties();
+ encryptionProperties.setStandardEncryption(new byte[16], new byte[16], 0, 0);
+ encryptor.setEncryptionProperties(encryptionProperties);
+
+ try (PdfReader initialFile = new PdfReader(initialFileName);
+ FileOutputStream outputStream = new FileOutputStream(outFileName)) {
+ encryptor.encrypt(initialFile, outputStream);
}
- Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder));
+ ReaderProperties readerProperties = new ReaderProperties();
+ readerProperties.setPassword(new byte[16]);
+ PdfReader outFile = new PdfReader(outFileName, readerProperties);
+ PdfDocument doc = new PdfDocument(outFile);
+ doc.close();
+ Assert.assertTrue(outFile.isEncrypted());
}
-}
+}
\ No newline at end of file
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfObjectReleaseTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfObjectReleaseTest.java
index 5750c243ed..d55577e4eb 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfObjectReleaseTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfObjectReleaseTest.java
@@ -35,10 +35,8 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfObjectReleaseTest extends ExtendedITextTest {
@@ -51,9 +49,6 @@ public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.FORBID_RELEASE_IS_SET, count = 108))
public void releaseObjectsInDocWithStructTreeRootTest() throws IOException, InterruptedException {
@@ -153,10 +148,11 @@ public void addingReleasedObjectToDocumentTest() throws IOException {
doc.getCatalog().put(PdfName.Outlines, releasedObj);
} finally {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage("Cannot write object after it was released."
- + " In normal situation the object must be read once again before being written.");
- doc.close();
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> doc.close()
+ );
+ Assert.assertEquals("Cannot write object after it was released."
+ + " In normal situation the object must be read once again before being written.", e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java
index 7646f258e4..afdd1e081e 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfOutlineTest.java
@@ -48,27 +48,20 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.navigation.PdfStringDestination;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
-import com.itextpdf.test.LogLevelConstants;
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.xml.sax.SAXException;
-
import javax.xml.parsers.ParserConfigurationException;
-
import java.io.FileOutputStream;
import java.io.IOException;
-
import java.util.ArrayList;
import java.util.List;
-
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfOutlineTest extends ExtendedITextTest {
@@ -76,9 +69,6 @@ public class PdfOutlineTest extends ExtendedITextTest {
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/PdfOutlineTest/";
public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/PdfOutlineTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void before() {
createOrClearDestinationFolder(DESTINATION_FOLDER);
@@ -226,12 +216,14 @@ public void updateOutlineTitle() throws IOException, InterruptedException {
@Test
public void getOutlinesInvalidParentLink() throws IOException, InterruptedException {
- junitExpectedException.expect(NullPointerException.class);
PdfReader reader = new PdfReader(SOURCE_FOLDER + "outlinesInvalidParentLink.pdf");
String filename = "updateOutlineTitleInvalidParentLink.pdf";
PdfWriter writer = new PdfWriter(DESTINATION_FOLDER + filename);
PdfDocument pdfDoc = new PdfDocument(reader, writer);
- PdfOutline outlines = pdfDoc.getOutlines(false);
+
+ Assert.assertThrows(NullPointerException.class,
+ () -> pdfDoc.getOutlines(false)
+ );
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java
index 5f6495d6a4..ea2019a926 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfPagesTest.java
@@ -60,10 +60,8 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -81,9 +79,6 @@ public class PdfPagesTest extends ExtendedITextTest {
private static final PdfName PageNum = new PdfName("PageNum");
private static final PdfName PageNum5 = new PdfName("PageNum");
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void setup() {
createDestinationFolder(destinationFolder);
@@ -228,9 +223,10 @@ public void insertFlushedPageTest() {
page.flush();
pdfDoc.removePage(page);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.FlushedPageCannotBeAddedOrInserted);
- pdfDoc.addPage(1, page);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> pdfDoc.addPage(1, page)
+ );
+ Assert.assertEquals(PdfException.FlushedPageCannotBeAddedOrInserted, e.getMessage());
}
@Test
@@ -244,9 +240,10 @@ public void addFlushedPageTest() {
page.flush();
pdfDoc.removePage(page);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.FlushedPageCannotBeAddedOrInserted);
- pdfDoc.addPage(page);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> pdfDoc.addPage(page)
+ );
+ Assert.assertEquals(PdfException.FlushedPageCannotBeAddedOrInserted, e.getMessage());
}
@Test
@@ -284,9 +281,10 @@ public void removeFlushedPageFromTaggedDocument() {
pdfDocument.addNewPage();
pdfDocument.getPage(1).flush();
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.FLUSHED_PAGE_CANNOT_BE_REMOVED);
- pdfDocument.removePage(1);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> pdfDocument.removePage(1)
+ );
+ Assert.assertEquals(PdfException.FLUSHED_PAGE_CANNOT_BE_REMOVED, e.getMessage());
}
}
@@ -297,9 +295,10 @@ public void removeFlushedPageFromDocumentWithAcroForm() {
pdfDocument.addNewPage();
pdfDocument.getPage(1).flush();
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.FLUSHED_PAGE_CANNOT_BE_REMOVED);
- pdfDocument.removePage(1);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> pdfDocument.removePage(1)
+ );
+ Assert.assertEquals(PdfException.FLUSHED_PAGE_CANNOT_BE_REMOVED, e.getMessage());
}
}
@@ -555,10 +554,8 @@ public void pageGetMediaBoxNotEnoughArgumentsTest() throws IOException {
PdfDocument pdfDoc = new PdfDocument(reader);
PdfPage pageOne = pdfDoc.getPage(1);
- junitExpectedException.expect(PdfException.class);
- junitExpectedException
- .expectMessage(MessageFormatUtil.format(PdfException.WRONGMEDIABOXSIZETOOFEWARGUMENTS, 3));
- pageOne.getPageSize();
+ Exception e = Assert.assertThrows(PdfException.class, () -> pageOne.getPageSize());
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.WRONGMEDIABOXSIZETOOFEWARGUMENTS, 3), e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderDecodeTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderDecodeTest.java
index aed4412d1d..6009fc3d9d 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderDecodeTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderDecodeTest.java
@@ -53,19 +53,14 @@ This file is part of the iText (R) project.
import java.io.FileInputStream;
import java.io.IOException;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfReaderDecodeTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfReaderDecodeTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void noMemoryHandlerTest() throws IOException {
try (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
@@ -132,10 +127,6 @@ public void customMemoryHandlerSingleTest() throws IOException {
MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler();
handler.setMaxSizeOfSingleDecompressedPdfStream(1000);
- junitExpectedException.expect(MemoryLimitsAwareException.class);
- junitExpectedException
- .expectMessage(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed);
-
try (PdfDocument pdfDocument = new PdfDocument(
new PdfReader(sourceFolder + "timing.pdf",
new ReaderProperties().setMemoryLimitsAwareHandler(handler)),
@@ -157,7 +148,10 @@ public void customMemoryHandlerSingleTest() throws IOException {
array.add(PdfName.Fl);
- PdfReader.decodeBytes(b, stream);
+ Exception e = Assert.assertThrows(MemoryLimitsAwareException.class,
+ () -> PdfReader.decodeBytes(b, stream)
+ );
+ Assert.assertEquals(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed, e.getMessage());
}
}
@@ -196,10 +190,6 @@ public void oneFilterCustomMemoryHandlerSingleTest() throws IOException {
@LogMessage(messageTemplate = LogMessageConstant.XREF_ERROR_WHILE_READING_TABLE_WILL_BE_REBUILT)
})
public void overriddenMemoryHandlerAllStreamsAreSuspiciousTest() throws IOException {
-
- junitExpectedException.expect(MemoryLimitsAwareException.class);
- junitExpectedException.expectMessage(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed);
-
MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler() {
@Override
public boolean isMemoryLimitsAwarenessRequiredOnDecompression(PdfArray filters) {
@@ -221,7 +211,10 @@ public boolean isMemoryLimitsAwarenessRequiredOnDecompression(PdfArray filters)
array.add(PdfName.Fl);
// Limit is reached, and the stream with one filter is considered to be suspicious
- PdfReader.decodeBytes(b, stream);
+ Exception e = Assert.assertThrows(MemoryLimitsAwareException.class,
+ () -> PdfReader.decodeBytes(b, stream)
+ );
+ Assert.assertEquals(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed, e.getMessage());
}
}
@@ -284,10 +277,6 @@ public void customMemoryHandlerSumTest() throws IOException {
MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler();
handler.setMaxSizeOfDecompressedPdfStreamsSum(100000);
- junitExpectedException.expect(MemoryLimitsAwareException.class);
- junitExpectedException
- .expectMessage(PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed);
-
try (PdfDocument pdfDocument = new PdfDocument(
new PdfReader(sourceFolder + "timing.pdf",
new ReaderProperties().setMemoryLimitsAwareHandler(handler)),
@@ -296,7 +285,10 @@ public void customMemoryHandlerSumTest() throws IOException {
PdfStream stream = pdfDocument.getFirstPage().getContentStream(0);
byte[] b = stream.getBytes(false);
- PdfReader.decodeBytes(b, stream);
+ Exception e = Assert.assertThrows(MemoryLimitsAwareException.class,
+ () -> PdfReader.decodeBytes(b, stream)
+ );
+ Assert.assertEquals(PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed, e.getMessage());
}
}
@@ -309,16 +301,15 @@ public void pageSumTest() throws IOException {
MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler();
handler.setMaxSizeOfDecompressedPdfStreamsSum(1500000);
- junitExpectedException.expect(MemoryLimitsAwareException.class);
- junitExpectedException
- .expectMessage(PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed);
-
try (PdfDocument pdfDocument = new PdfDocument(
new PdfReader(sourceFolder + "timing.pdf",
new ReaderProperties().setMemoryLimitsAwareHandler(handler)),
new PdfWriter(new ByteArrayOutputStream()))) {
- pdfDocument.getFirstPage().getContentBytes();
+ Exception e = Assert.assertThrows(MemoryLimitsAwareException.class,
+ () -> pdfDocument.getFirstPage().getContentBytes()
+ );
+ Assert.assertEquals(PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed, e.getMessage());
}
}
@@ -331,15 +322,15 @@ public void pageAsSingleStreamTest() throws IOException {
MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler();
handler.setMaxSizeOfSingleDecompressedPdfStream(1500000);
- junitExpectedException.expect(MemoryLimitsAwareException.class);
- junitExpectedException.expectMessage(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed);
-
try (PdfDocument pdfDocument = new PdfDocument(
new PdfReader(sourceFolder + "timing.pdf",
new ReaderProperties().setMemoryLimitsAwareHandler(handler)),
new PdfWriter(new ByteArrayOutputStream()))) {
- pdfDocument.getFirstPage().getContentBytes();
+ Exception e = Assert.assertThrows(MemoryLimitsAwareException.class,
+ () -> pdfDocument.getFirstPage().getContentBytes()
+ );
+ Assert.assertEquals(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed, e.getMessage());
}
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderTest.java
index 29c0b3d68a..710f103fcc 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfReaderTest.java
@@ -56,10 +56,8 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.IOException;
@@ -79,9 +77,6 @@ public class PdfReaderTest extends ExtendedITextTest {
static final String creator = "iText 6";
static final String title = "Empty iText 6 Document";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createDestinationFolder(destinationFolder);
@@ -1674,14 +1669,15 @@ public void wrongStructureFlushingTest() throws IOException {
@Test
public void readerReuseTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.PdfReaderHasBeenAlreadyUtilized);
-
String filename = sourceFolder + "hello.pdf";
PdfReader reader = new PdfReader(filename);
PdfDocument pdfDoc1 = new PdfDocument(reader);
- PdfDocument pdfDoc2 = new PdfDocument(reader);
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> new PdfDocument(reader)
+ );
+ Assert.assertEquals(PdfException.PdfReaderHasBeenAlreadyUtilized, e.getMessage());
}
@Test
@@ -1732,11 +1728,10 @@ private boolean objectTypeEqualTo(PdfObject object, PdfName type) {
@Test
public void hasRebuiltXrefPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader hasRebuiltXrefReader = pdfDocumentNotReadTestInit();
- hasRebuiltXrefReader.hasRebuiltXref();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> hasRebuiltXrefReader.hasRebuiltXref());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1756,11 +1751,10 @@ protected void readPdf() throws IOException {
@Test
public void hasHybridXrefPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader hasHybridXrefPdfReader = pdfDocumentNotReadTestInit();
- hasHybridXrefPdfReader.hasHybridXref();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> hasHybridXrefPdfReader.hasHybridXref());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1780,11 +1774,10 @@ protected void readPdf() throws IOException {
@Test
public void hasXrefStmPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader hasXrefStmReader = pdfDocumentNotReadTestInit();
- hasXrefStmReader.hasXrefStm();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> hasXrefStmReader.hasXrefStm());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1804,11 +1797,10 @@ protected void readPdf() throws IOException {
@Test
public void hasFixedXrefPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader hasFixedXrefReader = pdfDocumentNotReadTestInit();
- hasFixedXrefReader.hasFixedXref();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> hasFixedXrefReader.hasFixedXref());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1828,11 +1820,10 @@ protected void readPdf() throws IOException {
@Test
public void getLastXrefPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader getLastXrefReader = pdfDocumentNotReadTestInit();
- getLastXrefReader.getLastXref();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> getLastXrefReader.getLastXref());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1852,11 +1843,10 @@ protected void readPdf() throws IOException {
@Test
public void getPermissionsPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader getPermissionsReader = pdfDocumentNotReadTestInit();
- getPermissionsReader.getPermissions();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> getPermissionsReader.getPermissions());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1876,11 +1866,12 @@ protected void readPdf() throws IOException {
@Test
public void isOpenedWithFullPPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader isOpenedWithFullPReader = pdfDocumentNotReadTestInit();
- isOpenedWithFullPReader.isOpenedWithFullPermission();
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> isOpenedWithFullPReader.isOpenedWithFullPermission()
+ );
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1900,11 +1891,10 @@ protected void readPdf() throws IOException {
@Test
public void getCryptoModePdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader getCryptoModeReader = pdfDocumentNotReadTestInit();
- getCryptoModeReader.getCryptoMode();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> getCryptoModeReader.getCryptoMode());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1924,11 +1914,12 @@ protected void readPdf() throws IOException {
@Test
public void computeUserPasswordPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader computeUserPasswordReader = pdfDocumentNotReadTestInit();
- computeUserPasswordReader.computeUserPassword();
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> computeUserPasswordReader.computeUserPassword()
+ );
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1948,11 +1939,10 @@ protected void readPdf() throws IOException {
@Test
public void getOriginalFileIdPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader getOriginalFileIdReader = pdfDocumentNotReadTestInit();
- getOriginalFileIdReader.getOriginalFileId();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> getOriginalFileIdReader.getOriginalFileId());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1972,11 +1962,10 @@ protected void readPdf() throws IOException {
@Test
public void getModifiedFileIdPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader getModifiedFileIdReader = pdfDocumentNotReadTestInit();
- getModifiedFileIdReader.getModifiedFileId();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> getModifiedFileIdReader.getModifiedFileId());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -1996,11 +1985,10 @@ protected void readPdf() throws IOException {
@Test
public void isEncryptedPdfDocumentNotReadTest() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
PdfReader isEncryptedReader = pdfDocumentNotReadTestInit();
- isEncryptedReader.isEncrypted();
+
+ Exception e = Assert.assertThrows(PdfException.class, () -> isEncryptedReader.isEncrypted());
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
@Test
@@ -2031,10 +2019,8 @@ private PdfReader pdfDocumentNotReadTestInit() throws IOException {
}
private void readingNotCompletedTest(PdfReader reader) {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.DocumentHasNotBeenReadYet);
-
- PdfDocument document = new PdfDocument(reader);
+ Exception e = Assert.assertThrows(PdfException.class, () -> new PdfDocument(reader));
+ Assert.assertEquals(PdfException.DocumentHasNotBeenReadYet, e.getMessage());
}
/**
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamDecodeTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamDecodeTest.java
index 33941486d1..55ddf6d8d5 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamDecodeTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamDecodeTest.java
@@ -33,10 +33,8 @@ This file is part of the iText (R) project.
import java.util.Arrays;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfStreamDecodeTest extends ExtendedITextTest {
@@ -67,9 +65,6 @@ public class PdfStreamDecodeTest extends ExtendedITextTest {
(byte) 0x16, (byte) 0xad
};
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
@LogMessages(messages = {
@LogMessage(messageTemplate = KernelLogMessageConstant.DCTDECODE_FILTER_DECODING, logLevel = LogLevelConstants.INFO)
@@ -86,11 +81,10 @@ public void testJBIG2DecodeFilter() {
PdfStream pdfStream = new PdfStream(FLATE_DECODED_BYTES);
pdfStream.put(PdfName.Filter, new PdfArray(Arrays.asList((PdfObject) PdfName.FlateDecode, (PdfObject) PdfName.JBIG2Decode)));
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(
- PdfException.Filter1IsNotSupported, PdfName.JBIG2Decode));
-
- pdfStream.getBytes(true);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> pdfStream.getBytes(true)
+ );
+ Assert.assertEquals(MessageFormatUtil.format(PdfException.Filter1IsNotSupported, PdfName.JBIG2Decode), e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamTest.java
index 6400d07d84..ecdb258f27 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfStreamTest.java
@@ -54,10 +54,8 @@ This file is part of the iText (R) project.
import java.util.Collections;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfStreamTest extends ExtendedITextTest {
@@ -65,9 +63,6 @@ public class PdfStreamTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfStreamTest/";
public static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/PdfStreamTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void before() {
createOrClearDestinationFolder(destinationFolder);
@@ -146,19 +141,18 @@ public void indirectRefInFilterAndNoTaggedPdfTest() throws IOException {
}
@Test
- // TODO DEVSIX-1193 remove junitExpectedException and expected NullPointerException after fix
+ // TODO DEVSIX-1193 remove NullPointerException after fix
public void indirectFilterInCatalogTest() throws IOException {
String inFile = sourceFolder + "indFilterInCatalog.pdf";
PdfDocument doc = new PdfDocument(new PdfReader(inFile),
new PdfWriter(destinationFolder + "indFilterInCatalog.pdf"));
- junitExpectedException.expect(NullPointerException.class);
- doc.close();
+ Assert.assertThrows(NullPointerException.class, () -> doc.close());
}
@Test
- // TODO DEVSIX-1193 remove junitExpectedException after fix
+ // TODO DEVSIX-1193 remove NullPointerException after fix
public void indirectFilterFlushedBeforeStreamTest() throws IOException {
String inFile = sourceFolder + "indFilterInCatalog.pdf";
String out = destinationFolder + "indirectFilterFlushedBeforeStreamTest.pdf";
@@ -170,12 +164,11 @@ public void indirectFilterFlushedBeforeStreamTest() throws IOException {
PdfObject filterObject = pdfDoc.getPdfObject(6);
filterObject.flush();
- junitExpectedException.expect(NullPointerException.class);
- pdfDoc.close();
+ Assert.assertThrows(NullPointerException.class, () -> pdfDoc.close());
}
@Test
- // TODO DEVSIX-1193 remove junitExpectedException after fix
+ // TODO DEVSIX-1193 remove NullPointerException after fix
public void indirectFilterMarkedToBeFlushedBeforeStreamTest() throws IOException {
String inFile = sourceFolder + "indFilterInCatalog.pdf";
String out = destinationFolder + "indirectFilterMarkedToBeFlushedBeforeStreamTest.pdf";
@@ -190,9 +183,9 @@ public void indirectFilterMarkedToBeFlushedBeforeStreamTest() throws IOException
// The image stream will be marked as MUST_BE_FLUSHED after page is flushed.
pdfDoc.getFirstPage().getPdfObject().getIndirectReference().setState(PdfObject.MUST_BE_FLUSHED);
- junitExpectedException.expect(NullPointerException.class);
- writer.flushWaitingObjects(Collections.emptySet());
-
- pdfDoc.close();
+ Assert.assertThrows(NullPointerException.class,
+ () -> writer.flushWaitingObjects(Collections.emptySet())
+ );
+ Assert.assertThrows(NullPointerException.class, () -> pdfDoc.close());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java
index 7a7fa3f86c..80d485ee18 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/PdfXObjectTest.java
@@ -61,7 +61,6 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -72,16 +71,12 @@ This file is part of the iText (R) project.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfXObjectTest extends ExtendedITextTest{
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/PdfXObjectTest/";
public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/PdfXObjectTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
public static final String[] images = new String[]{SOURCE_FOLDER + "WP_20140410_001.bmp",
SOURCE_FOLDER + "WP_20140410_001.JPC",
SOURCE_FOLDER + "WP_20140410_001.jpg",
@@ -309,10 +304,12 @@ public void calculateProportionallyFitRectangleWithWidthTest() throws IOExceptio
@Test
@Category(UnitTest.class)
public void calculateProportionallyFitRectangleWithWidthForCustomXObjectTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage("PdfFormXObject or PdfImageXObject expected.");
PdfXObject pdfXObject = new CustomPdfXObject(new PdfStream());
- PdfXObject.calculateProportionallyFitRectangleWithWidth(pdfXObject, 0, 0, 20);
+
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> PdfXObject.calculateProportionallyFitRectangleWithWidth(pdfXObject, 0, 0, 20)
+ );
+ Assert.assertEquals("PdfFormXObject or PdfImageXObject expected.", e.getMessage());
}
@Test
@@ -348,10 +345,12 @@ public void calculateProportionallyFitRectangleWithHeightTest() throws IOExcepti
@Test
@Category(UnitTest.class)
public void calculateProportionallyFitRectangleWithHeightForCustomXObjectTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage("PdfFormXObject or PdfImageXObject expected.");
PdfXObject pdfXObject = new CustomPdfXObject(new PdfStream());
- PdfXObject.calculateProportionallyFitRectangleWithHeight(pdfXObject, 0, 0, 20);
+
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> PdfXObject.calculateProportionallyFitRectangleWithHeight(pdfXObject, 0, 0, 20)
+ );
+ Assert.assertEquals("PdfFormXObject or PdfImageXObject expected.", e.getMessage());
}
private static class CustomPdfXObject extends PdfXObject {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/action/PdfTargetTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/action/PdfTargetTest.java
index ba052c3156..06f88594e4 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/action/PdfTargetTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/action/PdfTargetTest.java
@@ -62,15 +62,11 @@ This file is part of the iText (R) project.
import java.io.ByteArrayOutputStream;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfTargetTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
@Test
public void createInstanceTest() {
@@ -209,9 +205,6 @@ public void setAnnotationWhichIsMissedOnThePageTest() {
@Test
public void setAnnotationWithoutPageTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.AnnotationShallHaveReferenceToPage);
-
try (PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
document.addNewPage();
@@ -219,7 +212,11 @@ public void setAnnotationWithoutPageTest() {
new Rectangle(0,0, 20, 20));
PdfTarget target = PdfTarget.create(new PdfDictionary());
- target.setAnnotation(annotation, document);
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> target.setAnnotation(annotation, document)
+ );
+ Assert.assertEquals(PdfException.AnnotationShallHaveReferenceToPage, e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/ImageMasksTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/ImageMasksTest.java
index 17f819c656..6f07448b18 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/ImageMasksTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/ImageMasksTest.java
@@ -58,19 +58,14 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class ImageMasksTest extends ExtendedITextTest {
private static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/canvas/ImageMasksTest/";
private static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/canvas/ImageMasksTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -209,9 +204,10 @@ public void sMaskMatteDifferentSizeOfImgTest() throws IOException, InterruptedEx
@Test
public void imageWithInvalidMaskTest() throws IOException {
ImageData mask = ImageDataFactory.create(sourceFolder + "mask.png");
- junitExpectedException.expect(com.itextpdf.io.IOException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format
- (com.itextpdf.io.IOException.ThisImageCanNotBeAnImageMask));
- mask.makeMask();
+
+ Exception e = Assert.assertThrows(com.itextpdf.io.IOException.class,
+ () -> mask.makeMask()
+ );
+ Assert.assertEquals(MessageFormatUtil.format(com.itextpdf.io.IOException.ThisImageCanNotBeAnImageMask), e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest.java
index b6995daabe..cba0e56c6f 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest.java
@@ -85,19 +85,14 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfCanvasColorTest extends ExtendedITextTest {
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest/";
public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/canvas/PdfCanvasColorTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(DESTINATION_FOLDER);
@@ -616,27 +611,26 @@ public void patternColorUncoloredSetTwiceTest() throws Exception {
@Test
public void patternColorUncoloredPatternCsUnitTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
-
PdfDocument doc = new PdfDocument(new PdfWriter(new java.io.ByteArrayOutputStream()));
PdfPattern.Tiling circle = new PdfPattern.Tiling(15, 15, 10, 20, false);
new PdfPatternCanvas(circle, doc).circle(7.5f, 7.5f, 2.5f).fill().release();
- new PatternColor(circle, new PdfSpecialCs.Pattern(), new float[0]);
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> new PatternColor(circle, new PdfSpecialCs.Pattern(), new float[0])
+ );
}
@Test
public void patternColorUncoloredPatternColorUnitTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
-
PdfDocument doc = new PdfDocument(new PdfWriter(new java.io.ByteArrayOutputStream()));
PdfPattern.Tiling circle = new PdfPattern.Tiling(15, 15, 10, 20, false);
new PdfPatternCanvas(circle, doc).circle(7.5f, 7.5f, 2.5f).fill().release();
PatternColor redCirclePattern = new PatternColor(circle, ColorConstants.RED);
- new PatternColor(circle, redCirclePattern);
+
+ Assert.assertThrows(IllegalArgumentException.class, () -> new PatternColor(circle, redCirclePattern));
}
private static int countSubstringOccurrences(String str, String findStr) {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest.java
index 28ebd47dc9..1bfe11bf14 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest.java
@@ -42,7 +42,6 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.kernel.pdf.canvas;
-import com.itextpdf.io.LogMessageConstant;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
@@ -51,8 +50,8 @@ This file is part of the iText (R) project.
import com.itextpdf.io.util.StreamUtil;
import com.itextpdf.io.util.UrlUtil;
import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFontFactory;
-import com.itextpdf.kernel.pdf.CompressionConstants;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
@@ -60,20 +59,16 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
-import com.itextpdf.kernel.pdf.PdfVersion;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.WriterProperties;
import com.itextpdf.kernel.pdf.canvas.wmf.WmfImageData;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
-import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
-import com.itextpdf.test.annotations.LogMessage;
-import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import java.awt.Toolkit;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -81,7 +76,6 @@ This file is part of the iText (R) project.
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -106,7 +100,7 @@ public static void beforeClass() {
}
@Test
- public void createSimpleCanvas() throws IOException, FileNotFoundException {
+ public void createSimpleCanvas() throws IOException {
final String author = "Alexander Chingarev";
final String creator = "iText 6";
@@ -135,6 +129,38 @@ public void createSimpleCanvas() throws IOException, FileNotFoundException {
reader.close();
}
+ @Test
+ public void canvasDrawArcsTest() throws IOException, InterruptedException {
+ String fileName = "canvasDrawArcsTest.pdf";
+ String output = destinationFolder + fileName;
+ String cmp = sourceFolder + "cmp_" + fileName;
+
+ try (PdfDocument doc = new PdfDocument(new PdfWriter(output))) {
+ PdfPage page = doc.addNewPage();
+ PdfCanvas canvas = new PdfCanvas(page);
+
+ canvas.setLineWidth(5);
+
+ canvas.setStrokeColor(ColorConstants.BLUE);
+ canvas.moveTo(10, 300);
+ canvas.lineTo(50, 300);
+ canvas.arc(100, 550, 200, 600, 90, -135);
+ canvas.closePath();
+ canvas.stroke();
+
+ canvas.setStrokeColor(ColorConstants.RED);
+ canvas.moveTo(210, 300);
+ canvas.lineTo(250, 300);
+ canvas.arcContinuous(300, 550, 400, 600, 90, -135);
+ canvas.closePath();
+ canvas.stroke();
+
+ canvas.release();
+ }
+
+ Assert.assertNull(new CompareTool().compareByContent(output, cmp, destinationFolder, "diff_"));
+ }
+
@Test
public void createSimpleCanvasWithDrawing() throws IOException {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest.java
index 096b92dc8e..eb7d595ebc 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest.java
@@ -65,19 +65,14 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfCanvasXObjectTest extends ExtendedITextTest {
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest/";
public static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/pdf/canvas/PdfCanvasXObjectTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createDestinationFolder(DESTINATION_FOLDER);
@@ -154,11 +149,14 @@ public void addImageXObjectAtTest() throws IOException, InterruptedException {
@Test
@Category(UnitTest.class)
public void addCustomXObjectAtTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage("PdfFormXObject or PdfImageXObject expected.");
PdfXObject pdfXObject = new CustomPdfXObject(new PdfStream());
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
- new PdfCanvas(document.addNewPage()).addXObjectAt(pdfXObject, 0, 0);
+
+ PdfCanvas canvas = new PdfCanvas(document.addNewPage());
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> canvas.addXObjectAt(pdfXObject, 0, 0)
+ );
+ Assert.assertEquals("PdfFormXObject or PdfImageXObject expected.", e.getMessage());
}
// addXObjectFittedIntoRectangle(PdfXObject, Rectangle) test block (use PdfXObject#calculateProportionallyFitRectangleWithWidth)
@@ -448,11 +446,14 @@ public void addFormXObjectRectangleLargerWithMatrixTest() throws IOException, I
@Test
@Category(UnitTest.class)
public void addCustomXObjectFittedIntoRectangleTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage("PdfFormXObject or PdfImageXObject expected.");
PdfXObject pdfXObject = new CustomPdfXObject(new PdfStream());
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
- new PdfCanvas(document.addNewPage()).addXObjectFittedIntoRectangle(pdfXObject, new Rectangle(0, 0, 0, 0));
+
+ PdfCanvas pdfCanvas = new PdfCanvas(document.addNewPage());
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> pdfCanvas.addXObjectFittedIntoRectangle(pdfXObject, new Rectangle(0, 0, 0, 0))
+ );
+ Assert.assertEquals("PdfFormXObject or PdfImageXObject expected.", e.getMessage());
}
// addXObject(PdfXObject) test block
@@ -571,11 +572,14 @@ public void addImageXObjectWithTransformationMatrixTest() throws IOException, I
@Test
@Category(UnitTest.class)
public void addCustomXObjectTest() {
- junitExpectedException.expect(IllegalArgumentException.class);
- junitExpectedException.expectMessage("PdfFormXObject or PdfImageXObject expected.");
PdfXObject pdfXObject = new CustomPdfXObject(new PdfStream());
PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
- new PdfCanvas(document.addNewPage()).addXObject(pdfXObject);
+
+ PdfCanvas canvas = new PdfCanvas(document.addNewPage());
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> canvas.addXObject(pdfXObject)
+ );
+ Assert.assertEquals("PdfFormXObject or PdfImageXObject expected.", e.getMessage());
}
private static class CustomPdfXObject extends PdfXObject {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest.java
index a56af9e998..9ac15b8477 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest.java
@@ -22,7 +22,9 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.kernel.pdf.canvas.parser;
+import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.geom.Rectangle;
+import com.itextpdf.kernel.geom.Vector;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
@@ -30,10 +32,13 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData;
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
+import com.itextpdf.kernel.pdf.canvas.parser.listener.IEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.ITextExtractionStrategy;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
+import java.util.ArrayList;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -110,6 +115,28 @@ public void type3FontsWithIdentityFontMatrixAndMultiplier() throws IOException,
Assert.assertNull(new CompareTool().compareByContent(outputPdf, sourceFolder + "cmp_type3FontsWithIdentityFontMatrixAndMultiplier.pdf", destinationFolder, "diff_"));
}
+ @Test
+ public void type3FontCustomFontMatrixAndFontBBoxTest() throws IOException {
+ String inputPdf = sourceFolder + "type3FontCustomFontMatrixAndFontBBox.pdf";
+
+ // Resultant rectangle is expected to be a bounding box over the text on the page.
+ Rectangle expectedRectangle = new Rectangle(10f, 97.84f, 14.400002f, 8.880005f);
+ List actualRectangles;
+
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPdf))) {
+ TextBBoxEventListener eventListener = new TextBBoxEventListener();
+ PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(eventListener);
+
+ PdfPage page = pdfDoc.getPage(1);
+ canvasProcessor.processPageContent(page);
+
+ actualRectangles = eventListener.getRectangles();
+ }
+
+ Assert.assertEquals(1, actualRectangles.size());
+ Assert.assertTrue(expectedRectangle.equalsWithEpsilon(actualRectangles.get(0)));
+ }
+
private static class CharacterPositionEventListener implements ITextExtractionStrategy {
float glyphWidth;
TextRenderInfo firstTextRenderInfo;
@@ -141,4 +168,31 @@ public Set getSupportedEvents() {
}
}
+ private static class TextBBoxEventListener implements IEventListener {
+ private final List rectangles = new ArrayList<>();
+
+ public List getRectangles() {
+ return rectangles;
+ }
+
+ @Override
+ public void eventOccurred(IEventData data, EventType type) {
+ if (EventType.RENDER_TEXT.equals(type)) {
+ TextRenderInfo renderInfo = (TextRenderInfo) data;
+ Vector startPoint = renderInfo.getDescentLine().getStartPoint();
+ Vector endPoint = renderInfo.getAscentLine().getEndPoint();
+ float x1 = Math.min(startPoint.get(0), endPoint.get(0));
+ float x2 = Math.max(startPoint.get(0), endPoint.get(0));
+ float y1 = Math.min(startPoint.get(1), endPoint.get(1));
+ float y2 = Math.max(startPoint.get(1), endPoint.get(1));
+ rectangles.add(new Rectangle(x1, y1, x2 - x1, y2 - y1));
+ }
+ }
+
+ @Override
+ public Set getSupportedEvents() {
+ return null;
+ }
+ }
+
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfCanvasProcessorIntegrationTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfCanvasProcessorIntegrationTest.java
index 4d04238e5a..1ec03d2f1c 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfCanvasProcessorIntegrationTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfCanvasProcessorIntegrationTest.java
@@ -58,6 +58,7 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IEventListener;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
+import com.itextpdf.kernel.pdf.canvas.parser.util.InlineImageParsingUtils.InlineImageParseException;
import com.itextpdf.kernel.pdf.colorspace.PdfColorSpace;
import com.itextpdf.kernel.pdf.colorspace.PdfSpecialCs;
import com.itextpdf.test.AssertUtil;
@@ -74,26 +75,28 @@ This file is part of the iText (R) project.
import java.util.Map;
import java.util.HashMap;
import org.junit.Assert;
+import org.junit.BeforeClass;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-
import java.io.IOException;
import java.util.Set;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfCanvasProcessorIntegrationTest extends ExtendedITextTest {
- public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/parser/PdfCanvasProcessorTest/";
+ private static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/parser/PdfCanvasProcessorTest/";
+
+ private static final String DESTINATION_FOLDER = "./target/test/com/itextpdf/kernel/parser/PdfCanvasProcessorTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
+ @BeforeClass
+ public static void setUp() {
+ createDestinationFolder(DESTINATION_FOLDER);
+ }
@Test
public void contentStreamProcessorTest() throws IOException {
- PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + "tableWithImageAndText.pdf"), new PdfWriter(new ByteArrayOutputStream()));
+ PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "tableWithImageAndText.pdf"), new PdfWriter(new ByteArrayOutputStream()));
StringBuilder pageEventsLog = new StringBuilder();
for (int i = 1; i <= document.getNumberOfPages(); ++i) {
@@ -105,7 +108,7 @@ public void contentStreamProcessorTest() throws IOException {
}
- byte[] logBytes = Files.readAllBytes(Paths.get(sourceFolder + "contentStreamProcessorTest_events_log.dat"));
+ byte[] logBytes = Files.readAllBytes(Paths.get(SOURCE_FOLDER + "contentStreamProcessorTest_events_log.dat"));
String expectedPageEventsLog = new String(logBytes, StandardCharsets.UTF_8);
Assert.assertEquals(expectedPageEventsLog, pageEventsLog.toString());
@@ -113,7 +116,7 @@ public void contentStreamProcessorTest() throws IOException {
@Test
public void processGraphicsStateResourceOperatorFillOpacityTest() throws IOException {
- PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + "transparentText.pdf"));
+ PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "transparentText.pdf"));
Float expOpacity = 0.5f;
Map textRenderInfo = new HashMap<>();
@@ -127,7 +130,7 @@ public void processGraphicsStateResourceOperatorFillOpacityTest() throws IOExcep
@Test
public void processGraphicsStateResourceOperatorStrokeOpacityTest() throws IOException {
- PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + "hiddenText.pdf"));
+ PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "hiddenText.pdf"));
Float expOpacity = 0.0f;
Map textRenderInfo = new HashMap<>();
@@ -142,7 +145,7 @@ public void processGraphicsStateResourceOperatorStrokeOpacityTest() throws IOExc
@Test
public void testClosingEmptyPath() throws IOException {
String fileName = "closingEmptyPath.pdf";
- PdfDocument document = new PdfDocument(new PdfReader(sourceFolder + fileName));
+ PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + fileName));
PdfCanvasProcessor processor = new PdfCanvasProcessor(new NoOpEventListener());
// Assert than no exception is thrown when an empty path is handled
AssertUtil.doesNotThrow(() -> processor.processPageContent(document.getPage(1)));
@@ -152,7 +155,7 @@ public void testClosingEmptyPath() throws IOException {
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.FAILED_TO_PROCESS_A_TRANSFORMATION_MATRIX, count = 1))
public void testNoninvertibleMatrix() throws IOException {
String fileName = "noninvertibleMatrix.pdf";
- PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + fileName));
+ PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + fileName));
LocationTextExtractionStrategy strategy = new LocationTextExtractionStrategy();
PdfCanvasProcessor processor = new PdfCanvasProcessor(strategy);
@@ -168,23 +171,20 @@ public void testNoninvertibleMatrix() throws IOException {
@Test
@Ignore("DEVSIX-3608: this test currently throws StackOverflowError, which cannot be caught in .NET")
public void parseCircularReferencesInResourcesTest() throws IOException {
- junitExpectedException.expect(StackOverflowError.class);
-
String fileName = "circularReferencesInResources.pdf";
- PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + fileName));
-
- PdfCanvasProcessor processor = new PdfCanvasProcessor(new NoOpEventListener());
- PdfPage page = pdfDocument.getFirstPage();
+ try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + fileName))) {
- processor.processPageContent(page);
+ PdfCanvasProcessor processor = new PdfCanvasProcessor(new NoOpEventListener());
+ PdfPage page = pdfDocument.getFirstPage();
- pdfDocument.close();
+ Assert.assertThrows(StackOverflowError.class, () -> processor.processPageContent(page));
+ }
}
@Test
@LogMessages(messages = @LogMessage(messageTemplate = KernelLogMessageConstant.UNABLE_TO_PARSE_COLOR_WITHIN_COLORSPACE))
public void patternColorParsingNotValidPdfTest() throws IOException {
- String inputFile = sourceFolder + "patternColorParsingNotValidPdfTest.pdf";
+ String inputFile = SOURCE_FOLDER + "patternColorParsingNotValidPdfTest.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(inputFile));
for (int i = 1; i <= pdfDocument.getNumberOfPages(); ++i) {
@@ -203,7 +203,7 @@ public void patternColorParsingNotValidPdfTest() throws IOException {
@Test
public void patternColorParsingValidPdfTest() throws IOException {
- String inputFile = sourceFolder + "patternColorParsingValidPdfTest.pdf";
+ String inputFile = SOURCE_FOLDER + "patternColorParsingValidPdfTest.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(inputFile));
for (int i = 1; i <= pdfDocument.getNumberOfPages(); ++i) {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfContentExtractionTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfContentExtractionTest.java
index 3aa39ec548..2369006d18 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfContentExtractionTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/PdfContentExtractionTest.java
@@ -31,25 +31,18 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import java.io.IOException;
-import org.junit.Rule;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfContentExtractionTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
private static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/parser/PdfContentExtractionTest/";
@Test
//TODO: remove the expected exception construct once the issue is fixed (DEVSIX-1279)
public void contentExtractionInDocWithBigCoordinatesTest() throws IOException {
- junitExpectedException.expect(ClipperException.class);
- junitExpectedException.expectMessage(ClipperExceptionConstant.COORDINATE_OUTSIDE_ALLOWED_RANGE);
-
String inputFileName = sourceFolder + "docWithBigCoordinates.pdf";
//In this document the CTM shrinks coordinates and this coordinates are large numbers.
// At the moment creation of this test clipper has a problem with handling large numbers
@@ -58,6 +51,10 @@ public void contentExtractionInDocWithBigCoordinatesTest() throws IOException {
PdfDocument pdfDocument = new PdfDocument(new PdfReader(inputFileName));
PdfDocumentContentParser contentParser = new PdfDocumentContentParser(pdfDocument);
- contentParser.processContent(1, new LocationTextExtractionStrategy());
+
+ Exception e = Assert.assertThrows(ClipperException.class,
+ () -> contentParser.processContent(1, new LocationTextExtractionStrategy())
+ );
+ Assert.assertEquals(ClipperExceptionConstant.COORDINATE_OUTSIDE_ALLOWED_RANGE, e.getMessage());
}
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/clipper/PolyNodeTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/clipper/PolyNodeTest.java
index e4b4a6888e..15ee4f5640 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/clipper/PolyNodeTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/clipper/PolyNodeTest.java
@@ -49,17 +49,12 @@ This file is part of the iText (R) project.
import java.util.List;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PolyNodeTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void addAndGetChildTest() {
PolyNode node = new PolyNode();
@@ -73,11 +68,11 @@ public void addAndGetChildTest() {
@Test
public void unmodifiableListOfChildsTest() {
- junitExpectedException.expect(UnsupportedOperationException.class);
PolyNode node = new PolyNode();
List childs = node.getChilds();
- childs.add(new PolyNode());
+
+ Assert.assertThrows(UnsupportedOperationException.class, () -> childs.add(new PolyNode()));
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtilsTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtilsTest.java
new file mode 100644
index 0000000000..29d352b66c
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/canvas/parser/util/InlineImageParsingUtilsTest.java
@@ -0,0 +1,154 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: Bruno Lowagie, Paulo Soares, et al.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.pdf.canvas.parser.util;
+
+import com.itextpdf.io.util.MessageFormatUtil;
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.pdf.PdfArray;
+import com.itextpdf.kernel.pdf.PdfDictionary;
+import com.itextpdf.kernel.pdf.PdfName;
+import com.itextpdf.kernel.pdf.PdfNumber;
+import com.itextpdf.kernel.pdf.PdfStream;
+import com.itextpdf.kernel.pdf.canvas.parser.util.InlineImageParsingUtils.InlineImageParseException;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.UnitTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+
+@Category(UnitTest.class)
+public class InlineImageParsingUtilsTest extends ExtendedITextTest {
+ @Rule
+ public ExpectedException junitExpectedException = ExpectedException.none();
+
+ @Test
+ public void iccBasedCsTest() {
+ PdfName colorSpace = PdfName.ICCBased;
+
+ PdfDictionary dictionary = new PdfDictionary();
+ PdfArray array = new PdfArray();
+ array.add(colorSpace);
+ PdfStream stream = new PdfStream();
+ stream.put(PdfName.N, new PdfNumber(4));
+ array.add(stream);
+ dictionary.put(colorSpace, array);
+
+ Assert.assertEquals(4, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, dictionary));
+ }
+
+ @Test
+ public void indexedCsTest() {
+ PdfName colorSpace = PdfName.Indexed;
+
+ PdfDictionary dictionary = new PdfDictionary();
+ PdfArray array = new PdfArray();
+ array.add(colorSpace);
+ dictionary.put(colorSpace, array);
+
+ Assert.assertEquals(1, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, dictionary));
+ }
+
+ @Test
+ public void csInDictAsNameTest() {
+ PdfName colorSpace = PdfName.ICCBased;
+
+ PdfDictionary dictionary = new PdfDictionary();
+ dictionary.put(colorSpace, PdfName.DeviceCMYK);
+
+ Assert.assertEquals(4, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, dictionary));
+ }
+
+ @Test
+ public void csInDictAsNameNullTest() {
+ PdfName colorSpace = PdfName.ICCBased;
+
+ PdfDictionary dictionary = new PdfDictionary();
+
+ junitExpectedException.expect(InlineImageParseException.class);
+ junitExpectedException.expectMessage(MessageFormatUtil.format(PdfException.UnexpectedColorSpace1, "/ICCBased"));
+ InlineImageParsingUtils.getComponentsPerPixel(colorSpace, dictionary);
+ }
+
+ @Test
+ public void notSupportedCsWithCsDictionaryTest() {
+ PdfName colorSpace = PdfName.ICCBased;
+
+ PdfDictionary dictionary = new PdfDictionary();
+ PdfArray array = new PdfArray();
+ array.add(PdfName.Pattern);
+ PdfStream stream = new PdfStream();
+ stream.put(PdfName.N, new PdfNumber(4));
+ array.add(stream);
+ dictionary.put(colorSpace, array);
+
+ junitExpectedException.expect(InlineImageParseException.class);
+ junitExpectedException.expectMessage(MessageFormatUtil.format(PdfException.UnexpectedColorSpace1, "/ICCBased"));
+ InlineImageParsingUtils.getComponentsPerPixel(colorSpace, dictionary);
+ }
+
+ @Test
+ public void nullCsTest() {
+ Assert.assertEquals(1, InlineImageParsingUtils.getComponentsPerPixel(null, null));
+ }
+
+ @Test
+ public void deviceGrayCsTest() {
+ PdfName colorSpace = PdfName.DeviceGray;
+ Assert.assertEquals(1, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, null));
+ }
+
+ @Test
+ public void deviceRGBCsTest() {
+ PdfName colorSpace = PdfName.DeviceRGB;
+ Assert.assertEquals(3, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, null));
+ }
+
+ @Test
+ public void deviceCMYKCsTest() {
+ PdfName colorSpace = PdfName.DeviceCMYK;
+ Assert.assertEquals(4, InlineImageParsingUtils.getComponentsPerPixel(colorSpace, null));
+ }
+}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionFieldTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionFieldTest.java
index adff107397..6e920e0f3b 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionFieldTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionFieldTest.java
@@ -49,21 +49,19 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfString;
+import com.itextpdf.kernel.pdf.canvas.parser.clipper.ClipperException;
+import com.itextpdf.kernel.pdf.canvas.parser.clipper.ClipperExceptionConstant;
+import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfCollectionFieldTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
private static final PdfName[] ALLOWED_PDF_NAMES = {
PdfName.D,
PdfName.N,
@@ -212,15 +210,13 @@ public void getUnsupportedTypeValueTest() {
final String stringValue = "string value";
final String fieldName = "fieldName";
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format(PdfException._1IsNotAnAcceptableValueForTheField2,
- stringValue, fieldName));
-
PdfCollectionField field = new PdfCollectionField(fieldName, PdfCollectionField.FILENAME);
// this line will throw an exception as getValue() method is not
// supported for subType which differs from S, N and D.
- field.getValue(stringValue);
+ Exception e = Assert.assertThrows(PdfException.class, () -> field.getValue(stringValue));
+ Assert.assertEquals(MessageFormatUtil.format(PdfException._1IsNotAnAcceptableValueForTheField2,
+ stringValue, fieldName), e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionItemTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionItemTest.java
index ac0a9f72db..5fd90939ea 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionItemTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionItemTest.java
@@ -51,19 +51,13 @@ This file is part of the iText (R) project.
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.type.UnitTest;
-import java.util.TimeZone;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfCollectionItemTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void addItemTest() {
final String fieldName = "fieldName";
@@ -188,8 +182,6 @@ public void addPrefixTest() {
@Test
public void addPrefixToEmptyFieldTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.YouMustSetAValueBeforeAddingAPrefix);
final String fieldName = "fieldName";
final String fieldPrefix = "fieldPrefix";
@@ -205,7 +197,10 @@ public void addPrefixToEmptyFieldTest() {
// this line will throw an exception as setPrefix() method may be called
// only if value was set previously
- item.setPrefix(fieldName, fieldPrefix);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> item.setPrefix(fieldName, fieldPrefix)
+ );
+ Assert.assertEquals(PdfException.YouMustSetAValueBeforeAddingAPrefix, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionSortTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionSortTest.java
index 5be32c10be..557fc0c5ce 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionSortTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/collection/PdfCollectionSortTest.java
@@ -48,15 +48,11 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfCollectionSortTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
@Test
public void oneKeyConstructorTest() {
@@ -91,19 +87,17 @@ public void sortOrderForOneKeyTest() {
@Test
public void incorrectSortOrderForOneKeyTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.YouNeedASingleBooleanForThisCollectionSortDictionary);
-
final String key = "testKey";
final boolean[] testAscendings = {true, false};
PdfCollectionSort sort = new PdfCollectionSort(key);
- sort.setSortOrder(testAscendings);
-
// this line will throw an exception as number of parameters of setSortOrder()
// method should be exactly the same as number of keys of PdfCollectionSort
// here we have one key but two params
- Assert.assertTrue(sort.getPdfObject().getAsBool(PdfName.A));
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> sort.setSortOrder(testAscendings)
+ );
+ Assert.assertEquals(PdfException.YouNeedASingleBooleanForThisCollectionSortDictionary, e.getMessage());
}
@Test
@@ -122,9 +116,6 @@ public void sortOrderForMultipleKeysTest() {
@Test
public void singleSortOrderForMultipleKeysTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.YouHaveToDefineABooleanArrayForThisCollectionSortDictionary);
-
final String[] keys = { "testKey1", "testKey2", "testKey3"};
final boolean testAscending = true;
@@ -133,14 +124,14 @@ public void singleSortOrderForMultipleKeysTest() {
// this line will throw an exception as number of parameters of setSortOrder()
// method should be exactly the same as number of keys of PdfCollectionSort
// here we have three keys but one param
- sort.setSortOrder(testAscending);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> sort.setSortOrder(testAscending)
+ );
+ Assert.assertEquals(PdfException.YouHaveToDefineABooleanArrayForThisCollectionSortDictionary, e.getMessage());
}
@Test
public void incorrectMultipleSortOrderForMultipleKeysTest() {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.NumberOfBooleansInTheArrayDoesntCorrespondWithTheNumberOfFields);
-
final String[] keys = { "testKey1", "testKey2", "testKey3"};
final boolean[] testAscendings = {true, false};
@@ -150,7 +141,10 @@ public void incorrectMultipleSortOrderForMultipleKeysTest() {
// this line will throw an exception as number of parameters of setSortOrder()
// method should be exactly the same as number of keys of PdfCollectionSort
// here we have three keys but two params
- sort.setSortOrder(testAscendings);
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> sort.setSortOrder(testAscendings)
+ );
+ Assert.assertEquals(PdfException.NumberOfBooleansInTheArrayDoesntCorrespondWithTheNumberOfFields, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/colorspace/PdfShadingTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/colorspace/PdfShadingTest.java
index 6e43a0df3a..a6e20ede2b 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/colorspace/PdfShadingTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/colorspace/PdfShadingTest.java
@@ -26,75 +26,70 @@ This file is part of the iText (R) project.
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
-import com.itextpdf.kernel.pdf.PdfNumberTest;
import com.itextpdf.kernel.pdf.colorspace.PdfDeviceCs.Rgb;
import com.itextpdf.kernel.pdf.colorspace.PdfShading.Axial;
import com.itextpdf.kernel.pdf.colorspace.PdfShading.Radial;
import com.itextpdf.kernel.pdf.colorspace.PdfShading.ShadingType;
-import com.itextpdf.kernel.pdf.function.PdfFunction;
import com.itextpdf.test.ExtendedITextTest;
-import com.itextpdf.test.annotations.type.IntegrationTest;
import com.itextpdf.test.annotations.type.UnitTest;
import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class PdfShadingTest extends ExtendedITextTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
@Test
public void axialShadingConstructorNullExtendArgumentTest() {
boolean[] extendArray = null;
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("extend");
- Axial axial = new Axial(
- new Rgb(), 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, new float[]{0.5f, 0.5f, 0.5f},
- extendArray
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new Axial(
+ new Rgb(), 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, new float[]{0.5f, 0.5f, 0.5f},
+ extendArray
+ )
);
+ Assert.assertEquals("extend", e.getMessage());
}
@Test
public void axialShadingConstructorInvalidExtendArgumentTest() {
boolean[] extendArray = new boolean[] {true};
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("extend");
- Axial axial = new Axial(
- new Rgb(), 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, new float[]{0.5f, 0.5f, 0.5f},
- extendArray
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new Axial(
+ new Rgb(), 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, new float[]{0.5f, 0.5f, 0.5f},
+ extendArray
+ )
);
+ Assert.assertEquals("extend", e.getMessage());
}
@Test
public void radialShadingConstructorNullExtendArgumentTest() {
boolean[] extendArray = null;
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("extend");
- new Radial(
- new Rgb(), 0f, 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, 10f, new float[]{0.5f, 0.5f, 0.5f},
- extendArray
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new Radial(
+ new Rgb(), 0f, 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, 10f, new float[]{0.5f, 0.5f, 0.5f},
+ extendArray
+ )
);
+ Assert.assertEquals("extend", e.getMessage());
}
@Test
public void radialShadingConstructorInvalidExtendArgumentTest() {
boolean[] extendArray = new boolean[] {true, false, false};
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("extend");
- new Radial(
- new Rgb(), 0f, 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, 10f, new float[]{0.5f, 0.5f, 0.5f},
- extendArray
+ Exception e = Assert.assertThrows(IllegalArgumentException.class,
+ () -> new Radial(
+ new Rgb(), 0f, 0f, 0f, new float[] {0f, 0f, 0f}, 0.5f, 0.5f, 10f, new float[]{0.5f, 0.5f, 0.5f},
+ extendArray
+ )
);
+ Assert.assertEquals("extend", e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/copy/PdfAnnotationCopyingTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/copy/PdfAnnotationCopyingTest.java
index 6b82074972..34d874a01c 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/copy/PdfAnnotationCopyingTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/copy/PdfAnnotationCopyingTest.java
@@ -46,10 +46,9 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class PdfAnnotationCopyingTest extends ExtendedITextTest {
@@ -57,19 +56,14 @@ public class PdfAnnotationCopyingTest extends ExtendedITextTest {
public static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/PdfAnnotationCopyingTest/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfAnnotationCopyingTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
@Test
- // TODO remove expected exception and thus enable assertions when DEVSIX-3585 is implemented
+ @Ignore("Unignore when DEVSIX-3585 would be implemented")
public void testCopyingPageWithAnnotationContainingPopupKey() throws IOException {
- junitExpectedException.expect(AssertionError.class);
-
String inFilePath = sourceFolder + "annotation-with-popup.pdf";
String outFilePath = destinationFolder + "copy-annotation-with-popup.pdf";
PdfDocument originalDocument = new PdfDocument(new PdfReader(inFilePath));
@@ -112,10 +106,8 @@ public void testCopyingPageWithAnnotationContainingPopupKey() throws IOException
}
@Test
- // TODO remove expected exception and thus enable assertions when DEVSIX-3585 is implemented
+ @Ignore("Unignore when DEVSIX-3585 would be implemented")
public void testCopyingPageWithAnnotationContainingIrtKey() throws IOException {
- junitExpectedException.expect(AssertionError.class);
-
String inFilePath = sourceFolder + "annotation-with-irt.pdf";
String outFilePath = destinationFolder + "copy-annotation-with-irt.pdf";
PdfDocument originalDocument = new PdfDocument(new PdfReader(inFilePath));
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/filters/ASCIIHexDecodeFilterTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/filters/ASCIIHexDecodeFilterTest.java
index c5b178047f..2f015c6251 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/filters/ASCIIHexDecodeFilterTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/filters/ASCIIHexDecodeFilterTest.java
@@ -30,19 +30,14 @@ This file is part of the iText (R) project.
import java.io.IOException;
import java.nio.file.Files;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(UnitTest.class)
public class ASCIIHexDecodeFilterTest extends ExtendedITextTest {
public static final String SOURCE_FILE =
"./src/test/resources/com/itextpdf/kernel/pdf/filters/ASCIIHex.bin";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void decodingTest() throws IOException {
File file = new File(SOURCE_FILE);
@@ -63,9 +58,11 @@ public void decodingTest() throws IOException {
@Test
public void decodingIllegalaCharacterTest() {
byte[] bytes = "4c6f72656d20697073756d2eg>".getBytes();
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.IllegalCharacterInAsciihexdecode);
- ASCIIHexDecodeFilter.ASCIIHexDecode(bytes);
+
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> ASCIIHexDecodeFilter.ASCIIHexDecode(bytes)
+ );
+ Assert.assertEquals(PdfException.IllegalCharacterInAsciihexdecode, e.getMessage());
}
@Test
diff --git a/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest.java b/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest.java
index 4a4fe74f1c..0fbcc72717 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest.java
@@ -77,10 +77,8 @@ This file is part of the iText (R) project.
import java.util.Set;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class GetImageBytesTest extends ExtendedITextTest {
@@ -88,9 +86,6 @@ public class GetImageBytesTest extends ExtendedITextTest {
private static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest/";
private static final String destinationFolder = "./target/test/com/itextpdf/kernel/pdf/xobject/GetImageBytesTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -199,17 +194,17 @@ public void extractByteAlignedG4TiffImageTest() throws IOException {
@Test
public void expectedByteAlignedTiffImageExtractionTest() throws IOException {
//Byte-aligned image is expected in pdf file, but in fact it's not
- junitExpectedException.expect(com.itextpdf.io.IOException.class);
- junitExpectedException.expectMessage(MessageFormatUtil.format
- (com.itextpdf.io.IOException.ExpectedTrailingZeroBitsForByteAlignedLines));
-
String inFileName = sourceFolder + "expectedByteAlignedTiffImageExtraction.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(inFileName));
ImageExtractor listener = new ImageExtractor();
PdfCanvasProcessor processor = new PdfCanvasProcessor(listener);
- processor.processPageContent(pdfDocument.getPage(1));
+
+ Exception e = Assert.assertThrows(com.itextpdf.io.IOException.class,
+ () -> processor.processPageContent(pdfDocument.getPage(1))
+ );
+ Assert.assertEquals(MessageFormatUtil.format(com.itextpdf.io.IOException.ExpectedTrailingZeroBitsForByteAlignedLines), e.getMessage());
}
private class ImageExtractor implements IEventListener {
diff --git a/kernel/src/test/java/com/itextpdf/kernel/utils/CompareToolTest.java b/kernel/src/test/java/com/itextpdf/kernel/utils/CompareToolTest.java
index d5f88a7d15..6d270b4778 100644
--- a/kernel/src/test/java/com/itextpdf/kernel/utils/CompareToolTest.java
+++ b/kernel/src/test/java/com/itextpdf/kernel/utils/CompareToolTest.java
@@ -43,34 +43,38 @@ This file is part of the iText (R) project.
package com.itextpdf.kernel.utils;
import com.itextpdf.io.IoExceptionMessage;
+import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.util.GhostscriptHelper;
import com.itextpdf.io.util.SystemUtil;
+import com.itextpdf.kernel.font.PdfFontFactory;
+import com.itextpdf.kernel.geom.Rectangle;
+import com.itextpdf.kernel.pdf.PdfArray;
+import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfPage;
+import com.itextpdf.kernel.pdf.PdfWriter;
+import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
+import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
+import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
import java.io.File;
+import java.io.IOException;
+import javax.xml.parsers.ParserConfigurationException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import org.xml.sax.SAXException;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-
@Category(IntegrationTest.class)
public class CompareToolTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/utils/CompareToolTest/";
public static final String destinationFolder = "./target/test/com/itextpdf/kernel/utils/CompareToolTest/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void setUp() {
createOrClearDestinationFolder(destinationFolder);
@@ -172,11 +176,13 @@ public void gsEnvironmentVariableIsNotSpecifiedExceptionTest() throws IOExceptio
@Test
public void gsEnvironmentVariableSpecifiedIncorrectlyTest() throws IOException, InterruptedException {
- junitExpectedException.expect(CompareTool.CompareToolExecutionException.class);
- junitExpectedException.expectMessage(IoExceptionMessage.GS_ENVIRONMENT_VARIABLE_IS_NOT_SPECIFIED);
String outPdf = sourceFolder + "simple_pdf.pdf";
String cmpPdf = sourceFolder + "cmp_simple_pdf.pdf";
- new CompareTool("unspecified", null).compareVisually(outPdf, cmpPdf, destinationFolder, "diff_");
+
+ Exception e = Assert.assertThrows(CompareTool.CompareToolExecutionException.class,
+ () -> new CompareTool("unspecified", null).compareVisually(outPdf, cmpPdf, destinationFolder, "diff_")
+ );
+ Assert.assertEquals(IoExceptionMessage.GS_ENVIRONMENT_VARIABLE_IS_NOT_SPECIFIED, e.getMessage());
}
@Test
@@ -218,4 +224,66 @@ public void compareVisuallyDiffTestTest() throws IOException, InterruptedExcepti
Assert.assertTrue(new File(destinationFolder + "diff_1.png").exists());
Assert.assertTrue(new File(destinationFolder + "diff_2.png").exists());
}
+
+ @Test
+ public void compareDiffFilesWithSameLinkAnnotationTest() throws IOException {
+ String firstPdf = destinationFolder + "firstPdf.pdf";
+ String secondPdf = destinationFolder + "secondPdf.pdf";
+ PdfDocument firstDocument = new PdfDocument(new PdfWriter(firstPdf));
+
+ PdfPage page1FirstDocument = firstDocument.addNewPage();
+ PdfCanvas canvas = new PdfCanvas(page1FirstDocument);
+ canvas.beginText();
+ canvas.setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 14);
+ canvas.moveText(100, 600);
+ canvas.showText("Page 1");
+ canvas.moveText(0, -30);
+ canvas.showText("Link to page 1. Click here!");
+ canvas.endText();
+ canvas.release();
+ page1FirstDocument.addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 560, 260, 25)).setDestination(
+ PdfExplicitDestination.createFit(page1FirstDocument)).setBorder(new PdfArray(new float[] {0, 0, 1})));
+ page1FirstDocument.flush();
+ firstDocument.close();
+
+ PdfDocument secondDocument = new PdfDocument(new PdfWriter(secondPdf));
+ PdfPage page1secondDocument = secondDocument.addNewPage();
+ canvas = new PdfCanvas(page1secondDocument);
+ canvas.beginText();
+ canvas.setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 14);
+ canvas.moveText(100, 600);
+ canvas.showText("Page 1 wit different Text");
+ canvas.moveText(0, -30);
+ canvas.showText("Link to page 1. Click here!");
+ canvas.endText();
+ canvas.release();
+ page1secondDocument.addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 560, 260, 25)).setDestination(
+ PdfExplicitDestination.createFit(page1secondDocument)).setBorder(new PdfArray(new float[] {0, 0, 1})));
+ page1secondDocument.flush();
+ secondDocument.close();
+
+ Assert.assertNull(new CompareTool().compareLinkAnnotations(firstPdf, secondPdf));
+ }
+
+ @Test
+ public void compareFilesWithDiffLinkAnnotationTest() throws IOException {
+ String firstPdf = destinationFolder + "outPdf.pdf";
+ String secondPdf = destinationFolder + "secondPdf.pdf";
+ PdfDocument firstDocument = new PdfDocument(new PdfWriter(firstPdf));
+ PdfDocument secondDocument = new PdfDocument(new PdfWriter(secondPdf));
+
+ PdfPage page1FirstDocument = firstDocument.addNewPage();
+ page1FirstDocument.addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 560, 400, 50)).setDestination(
+ PdfExplicitDestination.createFit(page1FirstDocument)).setBorder(new PdfArray(new float[] {0, 0, 1})));
+ page1FirstDocument.flush();
+ firstDocument.close();
+
+ PdfPage page1SecondDocument = secondDocument.addNewPage();
+ page1SecondDocument.addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 560, 260, 25)).setDestination(
+ PdfExplicitDestination.createFit(page1SecondDocument)).setBorder(new PdfArray(new float[] {0, 0, 1})));
+ page1SecondDocument.flush();
+ secondDocument.close();
+
+ Assert.assertNotNull(new CompareTool().compareLinkAnnotations(firstPdf, secondPdf));
+ }
}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/utils/SecurityTestXmlParserFactory.java b/kernel/src/test/java/com/itextpdf/kernel/utils/SecurityTestXmlParserFactory.java
new file mode 100644
index 0000000000..e2b00da7e1
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/utils/SecurityTestXmlParserFactory.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.utils;
+
+import com.itextpdf.kernel.PdfException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+public class SecurityTestXmlParserFactory extends DefaultSafeXmlParserFactory {
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ DocumentBuilder db;
+ try {
+ db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+
+ db.setEntityResolver(new TestEntityResolver());
+ return db;
+ }
+
+ private static class TestEntityResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) {
+ throw new PdfException("Test message");
+ }
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/test/java/com/itextpdf/kernel/utils/XmlProcessorCreatorSecurityTest.java b/kernel/src/test/java/com/itextpdf/kernel/utils/XmlProcessorCreatorSecurityTest.java
new file mode 100644
index 0000000000..a77097a3cc
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/utils/XmlProcessorCreatorSecurityTest.java
@@ -0,0 +1,227 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License version 3
+ as published by the Free Software Foundation with the addition of the
+ following permission added to Section 15 as permitted in Section 7(a):
+ FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
+ ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
+ OF THIRD PARTY RIGHTS
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses or write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA, 02110-1301 USA, or download the license from the following URL:
+ http://itextpdf.com/terms-of-use/
+
+ The interactive user interfaces in modified source and object code versions
+ of this program must display Appropriate Legal Notices, as required under
+ Section 5 of the GNU Affero General Public License.
+
+ In accordance with Section 7(b) of the GNU Affero General Public License,
+ a covered work must retain the producer line in every PDF that is created
+ or manipulated using iText.
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the iText software without
+ disclosing the source code of your own applications.
+ These activities include: offering paid services to customers as an ASP,
+ serving PDFs on the fly in a web application, shipping iText with a closed
+ source product.
+
+ For more information, please contact iText Software Corp. at this
+ address: sales@itextpdf.com
+ */
+package com.itextpdf.kernel.utils;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.test.ExceptionTestUtil;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.UnitTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+@Category(UnitTest.class)
+public class XmlProcessorCreatorSecurityTest extends ExtendedITextTest {
+
+ private static final String XML_WITHOUT_DTD = "\n"
+ + "\n"
+ + " Artem B\n"
+ + " Nikita K\n"
+ + "";
+
+ private static final String XML_WITH_DTD = "\n"
+ + "\n"
+ + " \n"
+ + "]>\n"
+ + "\n"
+ + " Artem B\n"
+ + " Nikita K\n"
+ + "";
+
+ private static final String XML_WITH_EMPTY_DTD = "\n"
+ + "\n"
+ + "\n"
+ + " Artem B\n"
+ + " Nikita K\n"
+ + "";
+
+ private static final String XML_WITH_INTERNAL_ENTITY = "\n"
+ + "\n"
+ + " \n"
+ + " \n"
+ + "]>\n"
+ + "\n"
+ + " Artem B &companyname;\n"
+ + " Nikita K &companyname;\n"
+ + "";
+
+ private static final String XML_WITH_XXE = "\n"
+ + "\n"
+ + " \n"
+ + " "
+ + "]>\n"
+ + "\n"
+ + " Artem B &xxe;\n"
+ + " Nikita K &xxe;\n"
+ + "";
+
+ private final static String DTD_EXCEPTION_MESSAGE = ExceptionTestUtil.getDoctypeIsDisallowedExceptionMessage();
+
+ @Before
+ public void resetXmlParserFactoryToDefault() {
+ XmlProcessorCreator.setXmlParserFactory(new DefaultSafeXmlParserFactory());
+ }
+
+ @Test
+ public void xmlWithoutDtd() throws ParserConfigurationException, IOException, SAXException {
+ Document document;
+ DocumentBuilder documentBuilder = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
+ try (InputStream inputStream = new ByteArrayInputStream(XML_WITHOUT_DTD.getBytes(StandardCharsets.UTF_8))) {
+ document = documentBuilder.parse(inputStream);
+ }
+ Assert.assertNotNull(document);
+ }
+
+ @Test
+ public void xmlWithXXECustomFactory() throws ParserConfigurationException, IOException, SAXException {
+ XmlProcessorCreator.setXmlParserFactory(new SecurityTestXmlParserFactory());
+ DocumentBuilder documentBuilder = XmlProcessorCreator.createSafeDocumentBuilder(false, false);
+ try (InputStream inputStream = new ByteArrayInputStream(XML_WITH_XXE.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> documentBuilder.parse(inputStream)
+ );
+ Assert.assertEquals("Test message", e.getMessage());
+ }
+ }
+
+ @Test
+ public void xmlWithDtd() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_DTD, false, false);
+ }
+
+ @Test
+ public void xmlWithEmptyDtdDtd() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_EMPTY_DTD, false, false);
+ }
+
+ @Test
+ public void xmlWithInternalEntity() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_INTERNAL_ENTITY, false, false);
+ }
+
+ @Test
+ public void xmlWithXXE() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_XXE, false, false);
+ }
+
+ @Test
+ public void xmlWithXXEFlags() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_XXE, true, true);
+ }
+
+ @Test
+ public void xmlWithXXEFlags2() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_XXE, true, false);
+ }
+
+ @Test
+ public void xmlWithXXEFlags3() throws ParserConfigurationException, IOException, SAXException {
+ createSafeDocumentBuilderTest(XML_WITH_XXE, false, true);
+ }
+
+ @Test
+ public void xmlWithXxeXMLReader() throws ParserConfigurationException, IOException, SAXException {
+ createSafeXMLReaderTest(true, true);
+ }
+
+ @Test
+ public void xmlWithXxeXMLReaderFlags() throws ParserConfigurationException, IOException, SAXException {
+ createSafeXMLReaderTest(false, false);
+ }
+
+ @Test
+ public void xmlWithXxeXMLReaderFlags2() throws ParserConfigurationException, IOException, SAXException {
+ createSafeXMLReaderTest(true, false);
+ }
+
+ @Test
+ public void xmlWithXxeXMLReaderFlags3() throws ParserConfigurationException, IOException, SAXException {
+ createSafeXMLReaderTest(false, true);
+ }
+
+ @Test
+ public void setXmlParserFactoryNull() throws IOException, SAXException {
+ XmlProcessorCreator.setXmlParserFactory(null);
+ createSafeDocumentBuilderTest(XML_WITH_XXE, false, false);
+ }
+
+ private void createSafeXMLReaderTest(boolean nameSpace, boolean validating)
+ throws IOException, SAXException {
+ XMLReader reader = XmlProcessorCreator.createSafeXMLReader(nameSpace, validating);
+ try (InputStream inputStream = new ByteArrayInputStream(
+ XmlProcessorCreatorSecurityTest.XML_WITH_XXE.getBytes(StandardCharsets.UTF_8))) {
+ InputSource inputSource = new InputSource(inputStream);
+ Exception e = Assert.assertThrows(SAXParseException.class,
+ () -> reader.parse(inputSource)
+ );
+ Assert.assertEquals(XmlProcessorCreatorSecurityTest.DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+
+ private void createSafeDocumentBuilderTest(String xml, boolean nameSpace, boolean comments)
+ throws IOException, SAXException {
+ DocumentBuilder documentBuilder = XmlProcessorCreator.createSafeDocumentBuilder(nameSpace, comments);
+ try (InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(SAXParseException.class,
+ () -> documentBuilder.parse(inputStream)
+ );
+ Assert.assertEquals(XmlProcessorCreatorSecurityTest.DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/SecurityTestXmlParserFactory.java b/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/SecurityTestXmlParserFactory.java
new file mode 100644
index 0000000000..aba960ff89
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/SecurityTestXmlParserFactory.java
@@ -0,0 +1,55 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.kernel.xmp.impl;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.kernel.utils.IXmlParserFactory;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+
+class SecurityTestXmlParserFactory extends DefaultSafeXmlParserFactory {
+ @Override
+ public DocumentBuilder createDocumentBuilderInstance(boolean namespaceAware, boolean ignoringComments) {
+ DocumentBuilder db;
+ try {
+ db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new PdfException(e.getMessage(), e);
+ }
+
+ db.setEntityResolver(new TestEmptyEntityResolver());
+ return db;
+ }
+
+ private static class TestEmptyEntityResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) {
+ throw new PdfException("Test message");
+ }
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserSecurityTest.java b/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserSecurityTest.java
new file mode 100644
index 0000000000..6eac168210
--- /dev/null
+++ b/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserSecurityTest.java
@@ -0,0 +1,96 @@
+/*
+ This file is part of the iText (R) project.
+ Copyright (c) 1998-2021 iText Group NV
+ Authors: iText Software.
+
+ This program is offered under a commercial and under the AGPL license.
+ For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
+
+ AGPL licensing:
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+package com.itextpdf.kernel.xmp.impl;
+
+import com.itextpdf.kernel.PdfException;
+import com.itextpdf.kernel.utils.DefaultSafeXmlParserFactory;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
+import com.itextpdf.kernel.xmp.XMPException;
+import com.itextpdf.test.ExceptionTestUtil;
+import com.itextpdf.test.ExtendedITextTest;
+import com.itextpdf.test.annotations.type.UnitTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(UnitTest.class)
+public class XMPMetaParserSecurityTest extends ExtendedITextTest {
+
+ private static final String XMP_WITH_XXE = "\n"
+ + " ]>\n"
+ + "\n"
+ + " \n"
+ + " \n"
+ + " &xxe;1\n"
+ + " B\n"
+ + " \n"
+ + " \n"
+ + "\n"
+ + "";
+
+ private static final String DTD_EXCEPTION_MESSAGE = ExceptionTestUtil.getDoctypeIsDisallowedExceptionMessage();
+
+ @Before
+ public void resetXmlParserFactoryToDefault() {
+ XmlProcessorCreator.setXmlParserFactory(new DefaultSafeXmlParserFactory());
+ }
+
+ @Test
+ public void xxeTestFromString() throws XMPException {
+ Exception e = Assert.assertThrows(XMPException.class, () -> XMPMetaParser.parse(XMP_WITH_XXE, null));
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+
+ @Test
+ public void xxeTestFromByteBuffer() throws XMPException {
+ Exception e = Assert.assertThrows(XMPException.class,
+ () -> XMPMetaParser.parse(XMP_WITH_XXE.getBytes(StandardCharsets.UTF_8), null)
+ );
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+
+ @Test
+ public void xxeTestFromInputStream() throws XMPException, IOException {
+ try (InputStream inputStream = new ByteArrayInputStream(XMP_WITH_XXE.getBytes(StandardCharsets.UTF_8))) {
+ Exception e = Assert.assertThrows(XMPException.class,
+ () -> XMPMetaParser.parse(inputStream, null)
+ );
+ Assert.assertEquals(DTD_EXCEPTION_MESSAGE, e.getMessage());
+ }
+ }
+
+ @Test
+ public void xxeTestFromStringCustomXmlParser() throws XMPException {
+ XmlProcessorCreator.setXmlParserFactory(new SecurityTestXmlParserFactory());
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> XMPMetaParser.parse(XMP_WITH_XXE, null)
+ );
+ Assert.assertEquals("Test message", e.getMessage());
+ }
+}
diff --git a/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserTest.java b/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserTest.java
deleted file mode 100644
index 2130b9a482..0000000000
--- a/kernel/src/test/java/com/itextpdf/kernel/xmp/impl/XMPMetaParserTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- This file is part of the iText (R) project.
- Copyright (c) 1998-2021 iText Group NV
- Authors: iText Software.
-
- This program is offered under a commercial and under the AGPL license.
- For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
-
- AGPL licensing:
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
- */
-package com.itextpdf.kernel.xmp.impl;
-
-import com.itextpdf.io.util.MessageFormatUtil;
-import com.itextpdf.kernel.xmp.XMPException;
-import com.itextpdf.kernel.xmp.XMPMeta;
-import com.itextpdf.kernel.xmp.XMPMetaFactory;
-import com.itextpdf.test.ExtendedITextTest;
-import com.itextpdf.test.annotations.type.UnitTest;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category(UnitTest.class)
-public class XMPMetaParserTest extends ExtendedITextTest {
-
- private static final String XXE_FILE_PATH = "./src/test/resources/com/itextpdf/kernel/xmp/impl/xxe-data.txt";
-
- private static final String XMP_WITH_XXE = "\n"
- + " ]>\n"
- + "\n"
- + " \n"
- + " \n"
- + " &xxe;1\n"
- + " B\n"
- + " \n"
- + " \n"
- + "\n"
- + "";
-
- private static final String EXPECTED_SERIALIZED_XMP = "\n"
- + "\n"
- + " \n"
- + " \n"
- + " \n"
- + "\n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + " \n"
- + "";
-
- @Test
- public void xxeTestFromString() throws XMPException {
- String metadataToParse = MessageFormatUtil.format(XMP_WITH_XXE, XXE_FILE_PATH);
- XMPMeta xmpMeta = XMPMetaParser.parse(metadataToParse, null);
- String serializedResult = XMPMetaFactory.serializeToString(xmpMeta, null);
- Assert.assertEquals(EXPECTED_SERIALIZED_XMP, serializedResult);
- }
-
- @Test
- public void xxeTestFromByteBuffer() throws XMPException {
- String metadataToParse = MessageFormatUtil.format(XMP_WITH_XXE, XXE_FILE_PATH);
- XMPMeta xmpMeta = XMPMetaParser.parse(metadataToParse.getBytes(StandardCharsets.UTF_8), null);
- String serializedResult = XMPMetaFactory.serializeToString(xmpMeta, null);
- Assert.assertEquals(EXPECTED_SERIALIZED_XMP, serializedResult);
- }
-
- @Test
- public void xxeTestFromInputStream() throws XMPException, IOException {
- String metadataToParse = MessageFormatUtil.format(XMP_WITH_XXE, XXE_FILE_PATH);
- try (InputStream inputStream = new ByteArrayInputStream(metadataToParse.getBytes(StandardCharsets.UTF_8))) {
- XMPMeta xmpMeta = XMPMetaParser.parse(inputStream, null);
- String serializedResult = XMPMetaFactory.serializeToString(xmpMeta, null);
- Assert.assertEquals(EXPECTED_SERIALIZED_XMP, serializedResult);
- }
- }
-}
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderAesEncryptionAddFileAttachment.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderAesEncryptionAddFileAttachment.pdf
new file mode 100644
index 0000000000..cb8cd44e4a
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderAesEncryptionAddFileAttachment.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddAnnotation.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddAnnotation.pdf
new file mode 100644
index 0000000000..585babf49d
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddAnnotation.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddFileAttachment.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddFileAttachment.pdf
new file mode 100644
index 0000000000..a2c29f7647
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_noReaderStandardEncryptionAddFileAttachment.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_readerWithoutEncryptionWriterStandardEncryption.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_readerWithoutEncryptionWriterStandardEncryption.pdf
new file mode 100644
index 0000000000..20cb9763de
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_readerWithoutEncryptionWriterStandardEncryption.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddAnnotation.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddAnnotation.pdf
new file mode 100644
index 0000000000..dbc6b6b878
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddAnnotation.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddFileAttachment.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddFileAttachment.pdf
new file mode 100644
index 0000000000..febe40e9a4
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/cmp_withReaderStandardEncryptionAddFileAttachment.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachmentAnnotations.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachmentAnnotations.pdf
new file mode 100644
index 0000000000..5faddbf408
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachmentAnnotations.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachments.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachments.pdf
new file mode 100644
index 0000000000..d4f38187d9
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithFileAttachments.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithUnencryptedAttachmentAnnotations.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithUnencryptedAttachmentAnnotations.pdf
new file mode 100644
index 0000000000..c66138c0aa
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/EncryptedEmbeddedStreamsHandlerTest/pdfWithUnencryptedAttachmentAnnotations.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/cmp_copyPagesLinkAnnotationTest.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/cmp_copyPagesLinkAnnotationTest.pdf
index 00fe82ff52..6311bc0120 100644
Binary files a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/cmp_copyPagesLinkAnnotationTest.pdf and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/cmp_copyPagesLinkAnnotationTest.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentUnitTest/pdfWithMetadata.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentUnitTest/pdfWithMetadata.pdf
new file mode 100644
index 0000000000..50886cb967
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfDocumentUnitTest/pdfWithMetadata.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfEncryptorTest/initial.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfEncryptorTest/initial.pdf
new file mode 100644
index 0000000000..4879f13edf
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/PdfEncryptorTest/initial.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest/cmp_canvasDrawArcsTest.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest/cmp_canvasDrawArcsTest.pdf
new file mode 100644
index 0000000000..e8374a47f4
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/PdfCanvasTest/cmp_canvasDrawArcsTest.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest/type3FontCustomFontMatrixAndFontBBox.pdf b/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest/type3FontCustomFontMatrixAndFontBBox.pdf
new file mode 100644
index 0000000000..325381ce33
Binary files /dev/null and b/kernel/src/test/resources/com/itextpdf/kernel/pdf/canvas/parser/GlyphBboxCalculationTest/type3FontCustomFontMatrixAndFontBBox.pdf differ
diff --git a/kernel/src/test/resources/com/itextpdf/kernel/xmp/impl/xxe-data.txt b/kernel/src/test/resources/com/itextpdf/kernel/xmp/impl/xxe-data.txt
deleted file mode 100644
index 629b2d444e..0000000000
--- a/kernel/src/test/resources/com/itextpdf/kernel/xmp/impl/xxe-data.txt
+++ /dev/null
@@ -1 +0,0 @@
-XXE FILE DATA
diff --git a/layout/pom.xml b/layout/pom.xml
index 9589b01174..475c8df257 100644
--- a/layout/pom.xml
+++ b/layout/pom.xml
@@ -4,7 +4,7 @@
com.itextpdfroot
- 7.1.15
+ 7.1.16layoutiText 7 - layout
diff --git a/layout/src/main/java/com/itextpdf/layout/Document.java b/layout/src/main/java/com/itextpdf/layout/Document.java
index 8fa6bec1b2..0a16d2b6f2 100644
--- a/layout/src/main/java/com/itextpdf/layout/Document.java
+++ b/layout/src/main/java/com/itextpdf/layout/Document.java
@@ -204,6 +204,10 @@ public void relayout() {
throw new IllegalStateException("Operation not supported with immediate flush");
}
+ if (rootRenderer instanceof DocumentRenderer) {
+ ((DocumentRenderer) rootRenderer).getTargetCounterHandler().prepareHandlerToRelayout();
+ }
+
IRenderer nextRelayoutRenderer = rootRenderer != null ? rootRenderer.getNextRenderer() : null;
if (nextRelayoutRenderer == null || !(nextRelayoutRenderer instanceof RootRenderer)) {
nextRelayoutRenderer = new DocumentRenderer(this, immediateFlush);
diff --git a/layout/src/main/java/com/itextpdf/layout/borders/Border.java b/layout/src/main/java/com/itextpdf/layout/borders/Border.java
index 1f3df8b4da..1ebcf40bc9 100644
--- a/layout/src/main/java/com/itextpdf/layout/borders/Border.java
+++ b/layout/src/main/java/com/itextpdf/layout/borders/Border.java
@@ -64,10 +64,6 @@ public abstract class Border {
*/
public static final Border NO_BORDER = null;
- /**
- * Value used by discontinuous borders during the drawing process
- */
- private static final float CURV = 0.447f;
/**
* The solid border.
*
@@ -129,6 +125,13 @@ public abstract class Border {
*/
public static final int DASHED_FIXED = 9;
+ private static final int ARC_RIGHT_DEGREE = 0;
+ private static final int ARC_TOP_DEGREE = 90;
+ private static final int ARC_LEFT_DEGREE = 180;
+ private static final int ARC_BOTTOM_DEGREE = 270;
+
+ private static final int ARC_QUARTER_CLOCKWISE_EXTENT = -90;
+
/**
* The color of the border.
*
@@ -487,34 +490,34 @@ protected float getDotsGap(double distance, float initialGap) {
* @param borderWidthAfter defines width of the border that is after the current one
*/
protected void drawDiscontinuousBorders(PdfCanvas canvas, Rectangle boundingRectangle, float[] horizontalRadii, float[] verticalRadii, Side defaultSide, float borderWidthBefore, float borderWidthAfter) {
- float x1 = boundingRectangle.getX();
- float y1 = boundingRectangle.getY();
- float x2 = boundingRectangle.getRight();
- float y2 = boundingRectangle.getTop();
+ double x1 = boundingRectangle.getX();
+ double y1 = boundingRectangle.getY();
+ double x2 = boundingRectangle.getRight();
+ double y2 = boundingRectangle.getTop();
- float horizontalRadius1 = horizontalRadii[0];
- float horizontalRadius2 = horizontalRadii[1];
+ final double horizontalRadius1 = horizontalRadii[0];
+ final double horizontalRadius2 = horizontalRadii[1];
- float verticalRadius1 = verticalRadii[0];
- float verticalRadius2 = verticalRadii[1];
+ final double verticalRadius1 = verticalRadii[0];
+ final double verticalRadius2 = verticalRadii[1];
// Points (x0, y0) and (x3, y3) are used to produce Bezier curve
- float x0 = boundingRectangle.getX();
- float y0 = boundingRectangle.getY();
- float x3 = boundingRectangle.getRight();
- float y3 = boundingRectangle.getTop();
+ double x0 = boundingRectangle.getX();
+ double y0 = boundingRectangle.getY();
+ double x3 = boundingRectangle.getRight();
+ double y3 = boundingRectangle.getTop();
- float innerRadiusBefore;
- float innerRadiusFirst;
- float innerRadiusSecond;
- float innerRadiusAfter;
+ double innerRadiusBefore;
+ double innerRadiusFirst;
+ double innerRadiusSecond;
+ double innerRadiusAfter;
- float widthHalf = width / 2;
+ final double widthHalf = width / 2.0;
Point clipPoint1;
Point clipPoint2;
Point clipPoint;
- Border.Side borderSide = getBorderSide(x1, y1, x2, y2, defaultSide);
+ final Border.Side borderSide = getBorderSide((float) x1, (float) y1, (float) x2, (float) y2, defaultSide);
switch (borderSide) {
case TOP:
@@ -547,9 +550,12 @@ protected void drawDiscontinuousBorders(PdfCanvas canvas, Rectangle boundingRect
y2 += widthHalf;
canvas
- .moveTo(x0, y0).curveTo(x0, y0 + innerRadiusFirst * CURV, x1 - innerRadiusBefore * CURV, y1, x1, y1)
- .lineTo(x2, y2)
- .curveTo(x2 + innerRadiusAfter * CURV, y2, x3, y3 + innerRadiusSecond * CURV, x3, y3);
+ .arc(x0, y0 - innerRadiusFirst,
+ x1 + innerRadiusBefore, y1,
+ ARC_LEFT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
+ .arcContinuous(x2 - innerRadiusAfter, y2,
+ x3, y3 - innerRadiusSecond,
+ ARC_TOP_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT);
break;
case RIGHT:
innerRadiusBefore = Math.max(0, verticalRadius1 - borderWidthBefore);
@@ -580,10 +586,12 @@ protected void drawDiscontinuousBorders(PdfCanvas canvas, Rectangle boundingRect
y2 += innerRadiusAfter;
canvas
- .moveTo(x0, y0).curveTo(x0 + innerRadiusFirst * CURV, y0, x1, y1 + innerRadiusBefore * CURV, x1, y1)
- .lineTo(x2, y2)
- .curveTo(x2, y2 - innerRadiusAfter * CURV, x3 + innerRadiusSecond * CURV, y3, x3, y3);
-
+ .arc(x0 - innerRadiusFirst, y0,
+ x1, y1 - innerRadiusBefore,
+ ARC_TOP_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
+ .arcContinuous(x2, y2 + innerRadiusAfter,
+ x3 - innerRadiusSecond, y3,
+ ARC_RIGHT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT);
break;
case BOTTOM:
innerRadiusBefore = Math.max(0, horizontalRadius1 - borderWidthBefore);
@@ -614,10 +622,12 @@ protected void drawDiscontinuousBorders(PdfCanvas canvas, Rectangle boundingRect
y2 -= widthHalf;
canvas
- .moveTo(x0, y0).curveTo(x0, y0 - innerRadiusFirst * CURV, x1 + innerRadiusBefore * CURV, y1, x1, y1)
- .lineTo(x2, y2)
- .curveTo(x2 - innerRadiusAfter * CURV, y2, x3, y3 - innerRadiusSecond * CURV, x3, y3);
-
+ .arc(x0, y0 + innerRadiusFirst,
+ x1 - innerRadiusBefore, y1,
+ ARC_RIGHT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
+ .arcContinuous(x2 + innerRadiusAfter, y2,
+ x3, y3 + innerRadiusSecond,
+ ARC_BOTTOM_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT);
break;
case LEFT:
innerRadiusBefore = Math.max(0, verticalRadius1 - borderWidthBefore);
@@ -648,9 +658,12 @@ protected void drawDiscontinuousBorders(PdfCanvas canvas, Rectangle boundingRect
y2 -= innerRadiusAfter;
canvas
- .moveTo(x0, y0).curveTo(x0 - innerRadiusFirst * CURV, y0, x1, y1 - innerRadiusBefore * CURV, x1, y1)
- .lineTo(x2, y2)
- .curveTo(x2, y2 + innerRadiusAfter * CURV, x3 - innerRadiusSecond * CURV, y3, x3, y3);
+ .arc(x0 + innerRadiusFirst, y0,
+ x1, y1 + innerRadiusBefore,
+ ARC_BOTTOM_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
+ .arcContinuous(x2, y2 - innerRadiusAfter,
+ x3 + innerRadiusSecond, y3,
+ ARC_LEFT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT);
break;
default:
break;
diff --git a/layout/src/main/java/com/itextpdf/layout/element/AbstractElement.java b/layout/src/main/java/com/itextpdf/layout/element/AbstractElement.java
index 909cd8dcba..5cfcfbe87c 100644
--- a/layout/src/main/java/com/itextpdf/layout/element/AbstractElement.java
+++ b/layout/src/main/java/com/itextpdf/layout/element/AbstractElement.java
@@ -132,6 +132,9 @@ public T1 getProperty(int property) {
* @return this element
*/
public T addStyle(Style style) {
+ if (style == null) {
+ throw new IllegalArgumentException("Style can not be null.");
+ }
if (styles == null) {
styles = new LinkedHashSet<>();
}
diff --git a/layout/src/main/java/com/itextpdf/layout/font/FontSelector.java b/layout/src/main/java/com/itextpdf/layout/font/FontSelector.java
index 95c1caace6..64b721539c 100644
--- a/layout/src/main/java/com/itextpdf/layout/font/FontSelector.java
+++ b/layout/src/main/java/com/itextpdf/layout/font/FontSelector.java
@@ -42,6 +42,8 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.layout.font;
+import com.itextpdf.io.font.FontProgramDescriptor;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -57,6 +59,8 @@ public class FontSelector {
private static final int EXPECTED_FONT_IS_BOLD_AWARD = 5;
private static final int EXPECTED_FONT_IS_NOT_BOLD_AWARD = 3;
+ private static final int EXPECTED_FONT_WEIGHT_IS_EQUALS_AWARD = 1;
+ private static final int EXPECTED_FONT_WEIGHT_IS_FAR_AWARD = 1;
private static final int EXPECTED_FONT_IS_ITALIC_AWARD = 5;
private static final int EXPECTED_FONT_IS_NOT_ITALIC_AWARD = 3;
private static final int EXPECTED_FONT_IS_MONOSPACED_AWARD = 5;
@@ -171,9 +175,10 @@ private static FontCharacteristics parseFontStyle(String fontFamily, FontCharact
*/
// TODO DEVSIX-2120 Update javadoc if necessary
private static int characteristicsSimilarity(String fontFamily, FontCharacteristics fc, FontInfo fontInfo, boolean isLastFontFamilyToBeProcessed) {
- boolean isFontBold = fontInfo.getDescriptor().isBold() || fontInfo.getDescriptor().getFontWeight() > 500;
- boolean isFontItalic = fontInfo.getDescriptor().isItalic() || fontInfo.getDescriptor().getItalicAngle() < 0;
- boolean isFontMonospace = fontInfo.getDescriptor().isMonospace();
+ FontProgramDescriptor fontDescriptor = fontInfo.getDescriptor();
+ boolean isFontBold = fontDescriptor.isBold() || fontDescriptor.getFontWeight() > 500;
+ boolean isFontItalic = fontDescriptor.isItalic() || fontDescriptor.getItalicAngle() < 0;
+ boolean isFontMonospace = fontDescriptor.isMonospace();
int score = 0;
// if font-family is monospace, serif or sans-serif, actual font's name shouldn't be checked
@@ -197,9 +202,9 @@ private static int characteristicsSimilarity(String fontFamily, FontCharacterist
// if alias is set, fontInfo's descriptor should not be checked
if (!"".equals(fontFamily)
&& (null == fontInfo.getAlias()
- && null != fontInfo.getDescriptor().getFamilyNameLowerCase()
- && fontInfo.getDescriptor().getFamilyNameLowerCase().equals(fontFamily)
- || (null != fontInfo.getAlias() && fontInfo.getAlias().toLowerCase().equals(fontFamily)))) {
+ && null != fontDescriptor.getFamilyNameLowerCase()
+ && fontDescriptor.getFamilyNameLowerCase().equals(fontFamily)
+ || (null != fontInfo.getAlias() && fontInfo.getAlias().toLowerCase().equals(fontFamily)))) {
score += FONT_FAMILY_EQUALS_AWARD;
} else {
if (!isLastFontFamilyToBeProcessed) {
@@ -209,6 +214,13 @@ private static int characteristicsSimilarity(String fontFamily, FontCharacterist
}
// calculate style characteristics
+ int maxWeight = Math.max(fontDescriptor.getFontWeight(), fc.getFontWeight());
+ int minWeight = Math.min(fontDescriptor.getFontWeight(), fc.getFontWeight());
+ if (maxWeight == minWeight) {
+ score += EXPECTED_FONT_WEIGHT_IS_EQUALS_AWARD;
+ } else if (maxWeight - minWeight >= 300) {
+ score -= EXPECTED_FONT_WEIGHT_IS_FAR_AWARD;
+ }
if (fc.isBold()) {
if (isFontBold) {
score += EXPECTED_FONT_IS_BOLD_AWARD;
diff --git a/layout/src/main/java/com/itextpdf/layout/hyphenation/PatternParser.java b/layout/src/main/java/com/itextpdf/layout/hyphenation/PatternParser.java
index 99b3bf1ec3..b00d05c00d 100644
--- a/layout/src/main/java/com/itextpdf/layout/hyphenation/PatternParser.java
+++ b/layout/src/main/java/com/itextpdf/layout/hyphenation/PatternParser.java
@@ -18,24 +18,20 @@
package com.itextpdf.layout.hyphenation;
import com.itextpdf.io.util.ResourceUtil;
+import com.itextpdf.kernel.utils.XmlProcessorCreator;
-import java.io.StringReader;
-import javax.xml.parsers.SAXParser;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
import org.xml.sax.Attributes;
-import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
-import javax.xml.parsers.SAXParserFactory;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
/**
* A SAX document handler to read and parse hyphenation patterns
* from a XML file.
@@ -118,14 +114,7 @@ public void parse(InputStream stream, String name) throws HyphenationException {
*/
static XMLReader createParser() {
try {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setValidating(false);
- factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
- SAXParser saxParser = factory.newSAXParser();
- XMLReader xmlReader = saxParser.getXMLReader();
- xmlReader.setEntityResolver(new SafeEmptyEntityResolver());
- return xmlReader;
+ return XmlProcessorCreator.createSafeXMLReader(true, false);
} catch (Exception e) {
// Converting checked exceptions to unchecked RuntimeException (java-specific comment).
//
@@ -436,12 +425,4 @@ private String getLocationString(SAXParseException ex) {
// getLocationString(SAXParseException):String
return str.toString();
}
-
- // Prevents XXE attacks
- private static class SafeEmptyEntityResolver implements EntityResolver {
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- }
-
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java
index 2266a79ec1..910aa8325a 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/AbstractRenderer.java
@@ -149,6 +149,13 @@ public abstract class AbstractRenderer implements IRenderer {
*/
static final int LEFT_SIDE = 3;
+ private static final int ARC_RIGHT_DEGREE = 0;
+ private static final int ARC_TOP_DEGREE = 90;
+ private static final int ARC_LEFT_DEGREE = 180;
+ private static final int ARC_BOTTOM_DEGREE = 270;
+
+ private static final int ARC_QUARTER_CLOCKWISE_EXTENT = -90;
+
// TODO linkedList?
protected List childRenderers = new ArrayList<>();
protected List positionedRenderers = new ArrayList<>();
@@ -767,8 +774,6 @@ private boolean clipArea(DrawContext drawContext, Rectangle outerBorderBox, bool
// border widths should be considered only once
assert false == considerBordersBeforeOuterClipping || false == considerBordersBeforeInnerClipping;
- final double curv = 0.4477f;
-
// border widths
float[] borderWidths = {0, 0, 0, 0};
// outer box
@@ -805,7 +810,7 @@ private boolean clipArea(DrawContext drawContext, Rectangle outerBorderBox, bool
// clip border area outside
if (clipOuter) {
- clipOuterArea(canvas, curv, horizontalRadii, verticalRadii, outerBox, cornersX, cornersY);
+ clipOuterArea(canvas, horizontalRadii, verticalRadii, outerBox, cornersX, cornersY);
}
if (considerBordersBeforeInnerClipping) {
@@ -814,28 +819,27 @@ private boolean clipArea(DrawContext drawContext, Rectangle outerBorderBox, bool
// clip border area inside
if (clipInner) {
- clipInnerArea(canvas, curv, horizontalRadii, verticalRadii, outerBox, cornersX, cornersY, borderWidths);
+ clipInnerArea(canvas, horizontalRadii, verticalRadii, outerBox, cornersX, cornersY, borderWidths);
}
}
return hasNotNullRadius;
}
- private void clipOuterArea(PdfCanvas canvas, double curv, float[] horizontalRadii, float[] verticalRadii, float[] outerBox, float[] cornersX, float[] cornersY) {
- float top = outerBox[0], right = outerBox[1],
- bottom = outerBox[2],
- left = outerBox[3];
-
- float x1 = cornersX[0], y1 = cornersY[0],
- x2 = cornersX[1], y2 = cornersY[1],
- x3 = cornersX[2], y3 = cornersY[2],
- x4 = cornersX[3], y4 = cornersY[3];
+ private void clipOuterArea(PdfCanvas canvas, float[] horizontalRadii, float[] verticalRadii,
+ float[] outerBox, float[] cornersX, float[] cornersY) {
+ final double top = outerBox[TOP_SIDE];
+ final double right = outerBox[RIGHT_SIDE];
+ final double bottom = outerBox[BOTTOM_SIDE];
+ final double left = outerBox[LEFT_SIDE];
// left top corner
if (0 != horizontalRadii[0] || 0 != verticalRadii[0]) {
+ double arcBottom = ((double) cornersY[TOP_SIDE]) - verticalRadii[TOP_SIDE];
+ double arcRight = ((double) cornersX[TOP_SIDE]) + horizontalRadii[TOP_SIDE];
canvas
.moveTo(left, bottom)
- .lineTo(left, y1)
- .curveTo(left, y1 + verticalRadii[0] * curv, x1 - horizontalRadii[0] * curv, top, x1, top)
+ .arcContinuous(left, arcBottom, arcRight, top,
+ ARC_LEFT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(right, top)
.lineTo(right, bottom)
.lineTo(left, bottom);
@@ -843,10 +847,12 @@ private void clipOuterArea(PdfCanvas canvas, double curv, float[] horizontalRadi
}
// right top corner
if (0 != horizontalRadii[1] || 0 != verticalRadii[1]) {
+ double arcLeft = ((double) cornersX[RIGHT_SIDE]) - horizontalRadii[RIGHT_SIDE];
+ double arcBottom = ((double) cornersY[RIGHT_SIDE]) - verticalRadii[RIGHT_SIDE];
canvas
.moveTo(left, top)
- .lineTo(x2, top)
- .curveTo(x2 + horizontalRadii[1] * curv, top, right, y2 + verticalRadii[1] * curv, right, y2)
+ .arcContinuous(arcLeft, top, right, arcBottom,
+ ARC_TOP_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(right, bottom)
.lineTo(left, bottom)
.lineTo(left, top);
@@ -854,10 +860,12 @@ private void clipOuterArea(PdfCanvas canvas, double curv, float[] horizontalRadi
}
// right bottom corner
if (0 != horizontalRadii[2] || 0 != verticalRadii[2]) {
+ double arcTop = ((double) cornersY[BOTTOM_SIDE]) + verticalRadii[BOTTOM_SIDE];
+ double arcLeft = ((double) cornersX[BOTTOM_SIDE]) - horizontalRadii[BOTTOM_SIDE];
canvas
.moveTo(right, top)
- .lineTo(right, y3)
- .curveTo(right, y3 - verticalRadii[2] * curv, x3 + horizontalRadii[2] * curv, bottom, x3, bottom)
+ .arcContinuous(right, arcTop, arcLeft, bottom,
+ ARC_RIGHT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(left, bottom)
.lineTo(left, top)
.lineTo(right, top);
@@ -865,10 +873,12 @@ private void clipOuterArea(PdfCanvas canvas, double curv, float[] horizontalRadi
}
// left bottom corner
if (0 != horizontalRadii[3] || 0 != verticalRadii[3]) {
+ double arcRight = ((double) cornersX[LEFT_SIDE]) + horizontalRadii[LEFT_SIDE];
+ double arcTop = ((double) cornersY[LEFT_SIDE]) + verticalRadii[LEFT_SIDE];
canvas
.moveTo(right, bottom)
- .lineTo(x4, bottom)
- .curveTo(x4 - horizontalRadii[3] * curv, bottom, left, y4 - verticalRadii[3] * curv, left, y4)
+ .arcContinuous(arcRight, bottom, left, arcTop,
+ ARC_BOTTOM_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(left, top)
.lineTo(right, top)
.lineTo(right, bottom);
@@ -876,26 +886,32 @@ private void clipOuterArea(PdfCanvas canvas, double curv, float[] horizontalRadi
}
}
- private void clipInnerArea(PdfCanvas canvas, double curv, float[] horizontalRadii, float[] verticalRadii, float[] outerBox, float[] cornersX, float[] cornersY, float[] borderWidths) {
- float top = outerBox[0],
- right = outerBox[1],
- bottom = outerBox[2],
- left = outerBox[3];
+ private void clipInnerArea(PdfCanvas canvas, float[] horizontalRadii, float[] verticalRadii,
+ float[] outerBox, float[] cornersX, float[] cornersY, float[] borderWidths) {
+ final double top = outerBox[TOP_SIDE];
+ final double right = outerBox[RIGHT_SIDE];
+ final double bottom = outerBox[BOTTOM_SIDE];
+ final double left = outerBox[LEFT_SIDE];
- float x1 = cornersX[0], y1 = cornersY[0],
- x2 = cornersX[1], y2 = cornersY[1],
- x3 = cornersX[2], y3 = cornersY[2],
- x4 = cornersX[3], y4 = cornersY[3];
- float topBorderWidth = borderWidths[0],
- rightBorderWidth = borderWidths[1],
- bottomBorderWidth = borderWidths[2],
- leftBorderWidth = borderWidths[3];
+ final double x1 = cornersX[TOP_SIDE];
+ final double y1 = cornersY[TOP_SIDE];
+ final double x2 = cornersX[RIGHT_SIDE];
+ final double y2 = cornersY[RIGHT_SIDE];
+ final double x3 = cornersX[BOTTOM_SIDE];
+ final double y3 = cornersY[BOTTOM_SIDE];
+ final double x4 = cornersX[LEFT_SIDE];
+ final double y4 = cornersY[LEFT_SIDE];
+ final double topBorderWidth = borderWidths[TOP_SIDE];
+ final double rightBorderWidth = borderWidths[RIGHT_SIDE];
+ final double bottomBorderWidth = borderWidths[BOTTOM_SIDE];
+ final double leftBorderWidth = borderWidths[LEFT_SIDE];
// left top corner
if (0 != horizontalRadii[0] || 0 != verticalRadii[0]) {
canvas
- .moveTo(left, y1)
- .curveTo(left, y1 + verticalRadii[0] * curv, x1 - horizontalRadii[0] * curv, top, x1, top)
+ .arc(left, y1 - verticalRadii[TOP_SIDE],
+ x1 + horizontalRadii[TOP_SIDE], top,
+ ARC_LEFT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(x2, top)
.lineTo(right, y2)
.lineTo(right, y3)
@@ -914,8 +930,9 @@ private void clipInnerArea(PdfCanvas canvas, double curv, float[] horizontalRadi
// right top corner
if (0 != horizontalRadii[1] || 0 != verticalRadii[1]) {
canvas
- .moveTo(x2, top)
- .curveTo(x2 + horizontalRadii[1] * curv, top, right, y2 + verticalRadii[1] * curv, right, y2)
+ .arc(x2 - horizontalRadii[RIGHT_SIDE], top, right,
+ y2 - verticalRadii[RIGHT_SIDE],
+ ARC_TOP_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(right, y3)
.lineTo(x3, bottom)
.lineTo(x4, bottom)
@@ -934,8 +951,9 @@ private void clipInnerArea(PdfCanvas canvas, double curv, float[] horizontalRadi
// right bottom corner
if (0 != horizontalRadii[2] || 0 != verticalRadii[2]) {
canvas
- .moveTo(right, y3)
- .curveTo(right, y3 - verticalRadii[2] * curv, x3 + horizontalRadii[2] * curv, bottom, x3, bottom)
+ .arc(right, y3 + verticalRadii[BOTTOM_SIDE],
+ x3 - horizontalRadii[BOTTOM_SIDE], bottom,
+ ARC_RIGHT_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(x4, bottom)
.lineTo(left, y4)
.lineTo(left, y1)
@@ -954,8 +972,9 @@ private void clipInnerArea(PdfCanvas canvas, double curv, float[] horizontalRadi
// left bottom corner
if (0 != horizontalRadii[3] || 0 != verticalRadii[3]) {
canvas
- .moveTo(x4, bottom)
- .curveTo(x4 - horizontalRadii[3] * curv, bottom, left, y4 - verticalRadii[3] * curv, left, y4)
+ .arc(x4 + horizontalRadii[LEFT_SIDE], bottom,
+ left, y4 + verticalRadii[LEFT_SIDE],
+ ARC_BOTTOM_DEGREE, ARC_QUARTER_CLOCKWISE_EXTENT)
.lineTo(left, y1)
.lineTo(x1, top)
.lineTo(x2, top)
@@ -1308,6 +1327,55 @@ protected static boolean isOverflowFit(OverflowPropertyValue rendererOverflowPro
return rendererOverflowProperty == null || OverflowPropertyValue.FIT.equals(rendererOverflowProperty);
}
+ /**
+ * Replaces given property own value with the given value.
+ *
+ * @param property the property to be replaced
+ * @param replacementValue the value with which property will be replaced
+ * @param the type associated with the property
+ * @return previous property value
+ */
+ T replaceOwnProperty(int property, T replacementValue) {
+ T ownProperty = this.getOwnProperty(property);
+ setProperty(property, replacementValue);
+ return ownProperty;
+ }
+
+ /**
+ * Returns back own value of the given property.
+ *
+ * @param property the property to be returned back
+ * @param prevValue the value which will be returned back
+ * @param the type associated with the property
+ */
+ void returnBackOwnProperty(int property, T prevValue) {
+ if (prevValue == null) {
+ deleteOwnProperty(property);
+ } else {
+ setProperty(property, prevValue);
+ }
+ }
+
+ /**
+ * Checks if this renderer has intrinsic aspect ratio.
+ *
+ * @return true, if aspect ratio is defined for this renderer, false otherwise
+ */
+ boolean hasAspectRatio() {
+ // TODO DEVSIX-5255 This method should be changed after we support aspect-ratio property
+ return false;
+ }
+
+ /**
+ * Gets intrinsic aspect ratio for this renderer.
+ *
+ * @return aspect ratio, if it is defined for this renderer, null otherwise
+ */
+ Float getAspectRatio() {
+ // TODO DEVSIX-5255 This method should be changed after we support aspect-ratio property
+ return null;
+ }
+
static void processWaitingDrawing(IRenderer child, Transform transformProp, List waitingDrawing) {
if (FloatingHelper.isRendererFloating(child) || transformProp != null) {
waitingDrawing.add(child);
@@ -2667,6 +2735,16 @@ void setThisAsParent(Collection children) {
}
}
+ boolean logWarningIfGetNextRendererNotOverridden(Class> baseClass, Class> rendererClass) {
+ if (baseClass != rendererClass) {
+ final Logger logger = LoggerFactory.getLogger(baseClass);
+ logger.warn(MessageFormatUtil.format(LogMessageConstant.GET_NEXT_RENDERER_SHOULD_BE_OVERRIDDEN));
+ return false;
+ } else {
+ return true;
+ }
+ }
+
private void removeThisFromParent(IRenderer toRemove) {
// we need to be sure that the removed element has no other entries in child renderers list
if (toRemove != null && this == toRemove.getParent() && !this.childRenderers.contains(toRemove)) {
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java
index a4ad9bbe83..14b60534fa 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java
@@ -977,6 +977,12 @@ void fixOccupiedAreaIfOverflowedY(OverflowPropertyValue overflowY, Rectangle lay
}
/**
+ * Decreases parentBBox to the size of borders, paddings and margins.
+ *
+ * @param parentBBox {@link Rectangle} to be decreased
+ * @param borders the border values to decrease parentBBox
+ * @param paddings the padding values to decrease parentBBox
+ * @return the difference between previous and current parentBBox's
* @deprecated Need to be removed in next major release.
*/
@Deprecated
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/CellRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/CellRenderer.java
index 7096a179a2..54e9a4fd6a 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/CellRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/CellRenderer.java
@@ -52,6 +52,7 @@ This file is part of the iText (R) project.
import com.itextpdf.layout.IPropertyContainer;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
+import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.property.BorderCollapsePropertyValue;
import com.itextpdf.layout.property.Property;
import com.itextpdf.layout.property.UnitValue;
@@ -201,10 +202,19 @@ protected Rectangle applySpacings(Rectangle rect, float[] spacings, boolean reve
}
/**
- * {@inheritDoc}
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link CellRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
*/
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(CellRenderer.class, this.getClass());
return new CellRenderer((Cell) getModelElement());
}
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/DivRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/DivRenderer.java
index 05bf46efc5..d2f64171e8 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/DivRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/DivRenderer.java
@@ -44,6 +44,7 @@ This file is part of the iText (R) project.
package com.itextpdf.layout.renderer;
import com.itextpdf.layout.element.Div;
+import com.itextpdf.layout.layout.LayoutContext;
public class DivRenderer extends BlockRenderer {
@@ -57,10 +58,19 @@ public DivRenderer(Div modelElement) {
}
/**
- * {@inheritDoc}
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link DivRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
*/
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(DivRenderer.class, this.getClass());
return new DivRenderer((Div) modelElement);
}
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/DocumentRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/DocumentRenderer.java
index 52e88b659f..073d811b20 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/DocumentRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/DocumentRenderer.java
@@ -108,7 +108,9 @@ public LayoutArea getOccupiedArea() {
*/
@Override
public IRenderer getNextRenderer() {
- return new DocumentRenderer(document, immediateFlush);
+ DocumentRenderer renderer = new DocumentRenderer(document, immediateFlush);
+ renderer.targetCounterHandler = new TargetCounterHandler(targetCounterHandler);
+ return renderer;
}
protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
@@ -117,7 +119,8 @@ protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
if (taggingHelper != null) {
taggingHelper.releaseFinishedHints();
}
- AreaBreak areaBreak = overflowResult != null && overflowResult.getAreaBreak() != null ? overflowResult.getAreaBreak() : null;
+ AreaBreak areaBreak = overflowResult != null && overflowResult.getAreaBreak() != null ?
+ overflowResult.getAreaBreak() : null;
if (areaBreak != null && areaBreak.getType() == AreaBreakType.LAST_PAGE) {
while (currentPageNumber < document.getPdfDocument().getNumberOfPages()) {
moveToNextPage();
@@ -126,7 +129,8 @@ protected LayoutArea updateCurrentArea(LayoutResult overflowResult) {
moveToNextPage();
}
PageSize customPageSize = areaBreak != null ? areaBreak.getPageSize() : null;
- while (document.getPdfDocument().getNumberOfPages() >= currentPageNumber && document.getPdfDocument().getPage(currentPageNumber).isFlushed()) {
+ while (document.getPdfDocument().getNumberOfPages() >= currentPageNumber &&
+ document.getPdfDocument().getPage(currentPageNumber).isFlushed()) {
currentPageNumber++;
}
PageSize lastPageSize = ensureDocumentHasNPages(currentPageNumber, customPageSize);
@@ -156,14 +160,16 @@ protected void flushSingleRenderer(IRenderer resultRenderer) {
}
boolean wrapOldContent = pdfDocument.getReader() != null && pdfDocument.getWriter() != null &&
- correspondingPage.getContentStreamCount() > 0 && correspondingPage.getLastContentStream().getLength() > 0 &&
+ correspondingPage.getContentStreamCount() > 0 &&
+ correspondingPage.getLastContentStream().getLength() > 0 &&
!wrappedContentPage.contains(pageNum) && pdfDocument.getNumberOfPages() >= pageNum;
wrappedContentPage.add(pageNum);
if (pdfDocument.isTagged()) {
pdfDocument.getTagStructureContext().getAutoTaggingPointer().setPageForTagging(correspondingPage);
}
- resultRenderer.draw(new DrawContext(pdfDocument, new PdfCanvas(correspondingPage, wrapOldContent), pdfDocument.isTagged()));
+ resultRenderer.draw(new DrawContext(pdfDocument,
+ new PdfCanvas(correspondingPage, wrapOldContent), pdfDocument.isTagged()));
}
}
@@ -178,7 +184,7 @@ protected PageSize addNewPage(PageSize customPageSize) {
/**
* Adds some pages so that the overall number is at least n.
- * Returns the page size of the n'th page.
+ * Returns the page size of the page number {@code n}.
*/
private PageSize ensureDocumentHasNPages(int n, PageSize customPageSize) {
PageSize lastPageSize = null;
@@ -200,8 +206,8 @@ private Rectangle getCurrentPageEffectiveArea(PageSize pageSize) {
}
private void moveToNextPage() {
- // We don't flush this page immediately, but only flush previous one because of manipulations with areas in case
- // of keepTogether property.
+ // We don't flush this page immediately, but only flush previous one because of manipulations
+ // with areas in case of keepTogether property.
if (immediateFlush && currentPageNumber > 1) {
document.getPdfDocument().getPage(currentPageNumber - 1).flush();
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/FlexContainerRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/FlexContainerRenderer.java
index c8030b5fa3..bcfd36cc4d 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/FlexContainerRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/FlexContainerRenderer.java
@@ -75,10 +75,19 @@ public FlexContainerRenderer(Div modelElement) {
}
/**
- * {@inheritDoc}
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link FlexContainerRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
*/
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(FlexContainerRenderer.class, this.getClass());
return new FlexContainerRenderer((Div) modelElement);
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/FlexUtil.java b/layout/src/main/java/com/itextpdf/layout/renderer/FlexUtil.java
index 48306df177..f0b6cfd179 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/FlexUtil.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/FlexUtil.java
@@ -43,6 +43,7 @@ This file is part of the iText (R) project.
*/
package com.itextpdf.layout.renderer;
+import com.itextpdf.io.LogMessageConstant;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.layout.exceptions.LayoutExceptionMessageConstant;
import com.itextpdf.layout.layout.LayoutArea;
@@ -54,6 +55,8 @@ This file is part of the iText (R) project.
import com.itextpdf.layout.property.JustifyContent;
import com.itextpdf.layout.property.Property;
import com.itextpdf.layout.property.UnitValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
@@ -66,6 +69,8 @@ final class FlexUtil {
private static final float FLEX_SHRINK_INITIAL_VALUE = 1F;
+ private static Logger logger = LoggerFactory.getLogger(FlexUtil.class);
+
private FlexUtil() {
// Do nothing
}
@@ -186,17 +191,24 @@ static void determineFlexBasisAndHypotheticalMainSizeForFlexItems(
for (FlexItemCalculationInfo info : flexItemCalculationInfos) {
// 3. Determine the flex base size and hypothetical main size of each item:
- // A. If the item has a definite used flex basis, that’s the flex base size.
- info.flexBaseSize = info.flexBasis;
+ AbstractRenderer renderer = info.renderer;
// TODO DEVSIX-5001 content as width are not supported
- // TODO DEVSIX-5004 Implement method to check whether an element has an intrinsic aspect ratio
// B. If the flex item has ...
// an intrinsic aspect ratio,
// a used flex basis of content, and
// a definite cross size,
// then the flex base size is calculated from its inner cross size
// and the flex item’s intrinsic aspect ratio.
+ Float rendererHeight = renderer.retrieveHeight();
+ if (renderer.hasAspectRatio() &&
+ info.flexBasisContent && rendererHeight != null) {
+ float aspectRatio = (float) renderer.getAspectRatio();
+ info.flexBaseSize = (float) rendererHeight * aspectRatio;
+ } else {
+ // A. If the item has a definite used flex basis, that’s the flex base size.
+ info.flexBaseSize = info.flexBasis;
+ }
// TODO DEVSIX-5001 content as width is not supported
// C. If the used flex basis is content or depends on its available space,
@@ -396,11 +408,20 @@ static void resolveFlexibleLengths(List> lines, fl
static void determineHypotheticalCrossSizeForFlexItems(List> lines) {
for (List line : lines) {
for (FlexItemCalculationInfo info : line) {
+ UnitValue prevWidth = info.renderer.replaceOwnProperty(Property.WIDTH,
+ UnitValue.createPointValue(info.mainSize));
+ UnitValue prevMinWidth = info.renderer.replaceOwnProperty(Property.MIN_WIDTH, null);
LayoutResult result = info.renderer.layout(new LayoutContext(
- new LayoutArea(0, new Rectangle(info.getOuterMainSize(info.mainSize), AbstractRenderer.INF))));
+ new LayoutArea(0, new Rectangle(AbstractRenderer.INF, AbstractRenderer.INF))));
+ info.renderer.returnBackOwnProperty(Property.MIN_WIDTH, prevMinWidth);
+ info.renderer.returnBackOwnProperty(Property.WIDTH, prevWidth);
// Since main size is clamped with min-width, we do expect the result to be full
- assert result.getStatus() == LayoutResult.FULL;
- info.hypotheticalCrossSize = info.getInnerCrossSize(result.getOccupiedArea().getBBox().getHeight());
+ if (result.getStatus() == LayoutResult.FULL) {
+ info.hypotheticalCrossSize = info.getInnerCrossSize(result.getOccupiedArea().getBBox().getHeight());
+ } else {
+ logger.error(LogMessageConstant.FLEX_ITEM_LAYOUT_RESULT_IS_NOT_FULL);
+ info.hypotheticalCrossSize = 0;
+ }
}
}
}
@@ -481,12 +502,15 @@ static void determineUsedCrossSizeOfEachFlexItem(ListgetProperty(
Property.ALIGN_SELF, alignItems);
// TODO DEVSIX-5002 Stretch value shall be ignored if margin auto for cross axis is set
- if (alignSelf == AlignmentPropertyValue.STRETCH || alignSelf == AlignmentPropertyValue.NORMAL) {
+ if ((alignSelf == AlignmentPropertyValue.STRETCH || alignSelf == AlignmentPropertyValue.NORMAL) &&
+ info.renderer.getProperty(Property.HEIGHT) == null) {
info.crossSize = info.getInnerCrossSize(lineCrossSizes.get(i));
Float maxHeight = infoRenderer.retrieveMaxHeight();
if (maxHeight != null) {
@@ -612,8 +636,10 @@ private static List createFlexItemCalculationInfos(
// TODO DEVSIX-5091 improve determining of the flex base size when flex-basis: content
float maxWidth = calculateMaxWidth(abstractRenderer, flexContainerWidth);
float flexBasis;
+ boolean flexBasisContent = false;
if (renderer.getProperty(Property.FLEX_BASIS) == null) {
flexBasis = maxWidth;
+ flexBasisContent = true;
} else {
flexBasis = (float) abstractRenderer.retrieveUnitValue(flexContainerWidth, Property.FLEX_BASIS);
if (AbstractRenderer.isBorderBoxSizing(abstractRenderer)) {
@@ -626,8 +652,8 @@ private static List createFlexItemCalculationInfos(
float flexShrink = (float) renderer.getProperty(Property.FLEX_SHRINK, FLEX_SHRINK_INITIAL_VALUE);
- final FlexItemCalculationInfo flexItemInfo = new FlexItemCalculationInfo(
- (AbstractRenderer) renderer, flexBasis, flexGrow, flexShrink, flexContainerWidth);
+ final FlexItemCalculationInfo flexItemInfo = new FlexItemCalculationInfo((AbstractRenderer) renderer,
+ flexBasis, flexGrow, flexShrink, flexContainerWidth, flexBasisContent);
flexItems.add(flexItemInfo);
}
@@ -649,9 +675,13 @@ private static float calculateMaxWidth(AbstractRenderer flexItemRenderer, float
maxWidth = flexItemRenderer.retrieveMaxWidth(flexContainerWidth);
}
if (maxWidth == null) {
- maxWidth = flexItemRenderer.getMinMaxWidth().getMaxWidth();
- maxWidth = flexItemRenderer.applyMarginsBordersPaddings(
- new Rectangle((float) maxWidth, 0), false).getWidth();
+ if (flexItemRenderer instanceof ImageRenderer) {
+ // TODO DEVSIX-5269 getMinMaxWidth doesn't always return the original image width
+ maxWidth = ((ImageRenderer) flexItemRenderer).getImageWidth();
+ } else {
+ maxWidth = flexItemRenderer.applyMarginsBordersPaddings(
+ new Rectangle(flexItemRenderer.getMinMaxWidth().getMaxWidth(), 0), false).getWidth();
+ }
}
}
return (float) maxWidth;
@@ -680,9 +710,11 @@ static class FlexItemCalculationInfo {
float flexBaseSize;
float hypotheticalMainSize;
float hypotheticalCrossSize;
+ boolean flexBasisContent;
public FlexItemCalculationInfo(AbstractRenderer renderer, float flexBasis,
- float flexGrow, float flexShrink, float areaWidth) {
+ float flexGrow, float flexShrink, float areaWidth, boolean flexBasisContent) {
+ this.flexBasisContent = flexBasisContent;
this.renderer = renderer;
this.flexBasis = flexBasis;
if (flexShrink < 0) {
@@ -693,21 +725,13 @@ public FlexItemCalculationInfo(AbstractRenderer renderer, float flexBasis,
throw new IllegalArgumentException(LayoutExceptionMessageConstant.FLEX_GROW_CANNOT_BE_NEGATIVE);
}
this.flexGrow = flexGrow;
- // We always need to clamp flex item's sizes with min-width, so this calculation is necessary
- // We also need to get min-width not based on Property.WIDTH
- final UnitValue rendererWidth = renderer.getOwnProperty(Property.WIDTH);
- final boolean hasOwnWidth = renderer.hasOwnProperty(Property.WIDTH);
- renderer.setProperty(Property.WIDTH, null);
- MinMaxWidth minMaxWidth = renderer.getMinMaxWidth();
- if (hasOwnWidth) {
- renderer.setProperty(Property.WIDTH, rendererWidth);
- } else {
- renderer.deleteOwnProperty(Property.WIDTH);
- }
- this.minContent = getInnerMainSize(minMaxWidth.getMinWidth());
- boolean isMaxWidthApplied = null != this.renderer.retrieveMaxWidth(areaWidth);
+ Float definiteMinContent = renderer.retrieveMinWidth(areaWidth);
+ // null means that min-width property is not set or has auto value. In both cases we should calculate it
+ this.minContent =
+ definiteMinContent == null ? calculateMinContentAuto(areaWidth) : (float) definiteMinContent;
+ Float maxWidth = this.renderer.retrieveMaxWidth(areaWidth);
// As for now we assume that max width should be calculated so
- this.maxContent = isMaxWidthApplied ? minMaxWidth.getMaxWidth() : AbstractRenderer.INF;
+ this.maxContent = maxWidth == null ? AbstractRenderer.INF : (float) maxWidth;
}
public Rectangle toRectangle() {
@@ -729,5 +753,107 @@ float getOuterCrossSize(float size) {
float getInnerCrossSize(float size) {
return renderer.applyMarginsBordersPaddings(new Rectangle(0, size), false).getHeight();
}
+
+ private float calculateMinContentAuto(float flexContainerWidth) {
+ // Automatic Minimum Size of Flex Items https://www.w3.org/TR/css-flexbox-1/#content-based-minimum-size
+ Float specifiedSizeSuggestion = calculateSpecifiedSizeSuggestion(flexContainerWidth);
+ float contentSizeSuggestion = calculateContentSizeSuggestion(flexContainerWidth);
+ if (renderer.hasAspectRatio() && specifiedSizeSuggestion == null) {
+ // However, if the box has an aspect ratio and no specified size,
+ // its content-based minimum size is the smaller of its content size suggestion
+ // and its transferred size suggestion
+ Float transferredSizeSuggestion = calculateTransferredSizeSuggestion();
+ if (transferredSizeSuggestion == null) {
+ return contentSizeSuggestion;
+ } else {
+ return Math.min(contentSizeSuggestion, (float) transferredSizeSuggestion);
+ }
+ } else if (specifiedSizeSuggestion == null) {
+ // If the box has neither a specified size suggestion nor an aspect ratio,
+ // its content-based minimum size is the content size suggestion.
+ return contentSizeSuggestion;
+ } else {
+ // In general, the content-based minimum size of a flex item is the smaller
+ // of its content size suggestion and its specified size suggestion
+ return Math.min(contentSizeSuggestion, (float) specifiedSizeSuggestion);
+ }
+ }
+
+ /**
+ * If the item has an intrinsic aspect ratio and its computed cross size property is definite,
+ * then the transferred size suggestion is that size (clamped by its min and max cross size properties
+ * if they are definite), converted through the aspect ratio. It is otherwise undefined.
+ *
+ * @return transferred size suggestion if it can be calculated, null otherwise
+ */
+ private Float calculateTransferredSizeSuggestion() {
+ Float transferredSizeSuggestion = null;
+ Float height = renderer.retrieveHeight();
+ if (renderer.hasAspectRatio() && height != null) {
+ transferredSizeSuggestion = height * renderer.getAspectRatio();
+
+ transferredSizeSuggestion =
+ clampValueByCrossSizesConvertedThroughAspectRatio((float) transferredSizeSuggestion);
+ }
+ return transferredSizeSuggestion;
+ }
+
+ /**
+ * If the item’s computed main size property is definite,
+ * then the specified size suggestion is that size (clamped by its max main size property if it’s definite).
+ * It is otherwise undefined.
+ *
+ * @param flexContainerWidth the width of the flex container
+ * @return specified size suggestion if it's definite, null otherwise
+ */
+ private Float calculateSpecifiedSizeSuggestion(float flexContainerWidth) {
+ if (renderer.hasProperty(Property.WIDTH)) {
+ return renderer.retrieveWidth(flexContainerWidth);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * The content size suggestion is the min-content size in the main axis, clamped, if it has an aspect ratio,
+ * by any definite min and max cross size properties converted through the aspect ratio,
+ * and then further clamped by the max main size property if that is definite.
+ *
+ * @param flexContainerWidth the width of the flex container
+ * @return content size suggestion
+ */
+ private float calculateContentSizeSuggestion(float flexContainerWidth) {
+ final UnitValue rendererWidth = renderer.replaceOwnProperty(Property.WIDTH, null);
+ final UnitValue rendererHeight = renderer.replaceOwnProperty(Property.HEIGHT, null);
+ MinMaxWidth minMaxWidth = renderer.getMinMaxWidth();
+ float minContentSize = getInnerMainSize(minMaxWidth.getMinWidth());
+ renderer.returnBackOwnProperty(Property.HEIGHT, rendererHeight);
+ renderer.returnBackOwnProperty(Property.WIDTH, rendererWidth);
+
+ if (renderer.hasAspectRatio()) {
+ minContentSize = clampValueByCrossSizesConvertedThroughAspectRatio(minContentSize);
+ }
+ Float maxWidth = renderer.retrieveMaxWidth(flexContainerWidth);
+ if (maxWidth == null) {
+ maxWidth = AbstractRenderer.INF;
+ }
+
+ return Math.min(minContentSize, (float) maxWidth);
+ }
+
+ private float clampValueByCrossSizesConvertedThroughAspectRatio(float value) {
+ Float maxHeight = renderer.retrieveMaxHeight();
+ if (maxHeight == null || !renderer.hasProperty(Property.MAX_HEIGHT)) {
+ maxHeight = AbstractRenderer.INF;
+ }
+ Float minHeight = renderer.retrieveMinHeight();
+ if (minHeight == null || !renderer.hasProperty(Property.MIN_HEIGHT)) {
+ minHeight = 0F;
+ }
+
+ return Math.min(
+ Math.max((float) (minHeight * renderer.getAspectRatio()), value),
+ (float) (maxHeight * renderer.getAspectRatio()));
+ }
}
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ImageRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ImageRenderer.java
index f013b693b1..a07232c999 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/ImageRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/ImageRenderer.java
@@ -101,6 +101,8 @@ public class ImageRenderer extends AbstractRenderer implements ILeafElementRende
*/
public ImageRenderer(Image image) {
super(image);
+ imageWidth = image.getImageWidth();
+ imageHeight = image.getImageHeight();
}
@Override
@@ -111,8 +113,6 @@ public LayoutResult layout(LayoutContext layoutContext) {
AffineTransform t = new AffineTransform();
Image modelElement = (Image) (getModelElement());
PdfXObject xObject = modelElement.getXObject();
- imageWidth = modelElement.getImageWidth();
- imageHeight = modelElement.getImageHeight();
calculateImageDimensions(layoutBox, t, xObject);
@@ -390,6 +390,40 @@ public Rectangle getBorderAreaBBox() {
return initialOccupiedAreaBBox;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ boolean hasAspectRatio() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ Float getAspectRatio() {
+ return imageWidth / imageHeight;
+ }
+
+ /**
+ * Gets original width of the image, not the width set by {@link Image#setWidth} method.
+ *
+ * @return original image width
+ */
+ public float getImageWidth() {
+ return imageWidth;
+ }
+
+ /**
+ * Gets original height of the image, not the height set by {@link Image#setHeight} method.
+ *
+ * @return original image height
+ */
+ public float getImageHeight() {
+ return imageHeight;
+ }
+
@Override
protected Rectangle applyPaddings(Rectangle rect, UnitValue[] paddings, boolean reverse) {
return rect;
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/LinkRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/LinkRenderer.java
index 111227cf0d..7650e51623 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/LinkRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/LinkRenderer.java
@@ -49,6 +49,7 @@ This file is part of the iText (R) project.
import org.slf4j.LoggerFactory;
import com.itextpdf.io.util.MessageFormatUtil;
+import com.itextpdf.layout.layout.LayoutContext;
public class LinkRenderer extends TextRenderer {
@@ -88,8 +89,20 @@ public void draw(DrawContext drawContext) {
}
+ /**
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link LinkRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
+ */
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(LinkRenderer.class, this.getClass());
return new LinkRenderer((Link) modelElement);
}
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java
index 4eb069614d..b7c59adff5 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/ListRenderer.java
@@ -103,8 +103,20 @@ public LayoutResult layout(LayoutContext layoutContext) {
return result;
}
+ /**
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link ListRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
+ */
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(ListRenderer.class, this.getClass());
return new ListRenderer((com.itextpdf.layout.element.List) modelElement);
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java
index 82bf6c524e..32ec0d3198 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/ParagraphRenderer.java
@@ -67,6 +67,7 @@ This file is part of the iText (R) project.
import com.itextpdf.layout.property.RenderingMode;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
+
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
@@ -501,10 +502,19 @@ protected LayoutResult directLayout(LayoutContext layoutContext) {
}
/**
- * {@inheritDoc}
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link ParagraphRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
*/
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(ParagraphRenderer.class, this.getClass());
return new ParagraphRenderer((Paragraph) modelElement);
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TabRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/TabRenderer.java
index 68edde17a5..6fc9cfe704 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/TabRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/TabRenderer.java
@@ -106,8 +106,20 @@ public void draw(DrawContext drawContext) {
}
}
+ /**
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link TabRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
+ */
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(TabRenderer.class, this.getClass());
return new TabRenderer((Tab) modelElement);
}
}
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java
index 302d889381..05c7e8eb06 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/TableRenderer.java
@@ -1194,10 +1194,19 @@ public void drawBackground(DrawContext drawContext) {
}
/**
- * {@inheritDoc}
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If a renderer overflows to the next area, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link TableRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created.
+ * @return new renderer instance
*/
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(TableRenderer.class, this.getClass());
TableRenderer nextTable = new TableRenderer();
nextTable.modelElement = modelElement;
return nextTable;
diff --git a/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java b/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java
index c35e893342..496c8fd3c2 100644
--- a/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java
+++ b/layout/src/main/java/com/itextpdf/layout/renderer/TextRenderer.java
@@ -196,6 +196,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
FloatingHelper.adjustFloatedBlockLayoutBox(this, layoutBox, null, floatRendererAreas, floatPropertyValue, overflowX);
}
+ float preMarginBorderPaddingWidth = layoutBox.getWidth();
UnitValue[] margins = getMargins();
applyMargins(layoutBox, margins, false);
Border[] borders = getBorders();
@@ -204,7 +205,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
UnitValue[] paddings = getPaddings();
applyPaddings(layoutBox, paddings, false);
- MinMaxWidth countedMinMaxWidth = new MinMaxWidth(area.getBBox().getWidth() - layoutBox.getWidth());
+ MinMaxWidth countedMinMaxWidth = new MinMaxWidth(preMarginBorderPaddingWidth - layoutBox.getWidth());
AbstractWidthHandler widthHandler;
if (noSoftWrap) {
widthHandler = new SumSumWidthHandler(countedMinMaxWidth);
@@ -1204,8 +1205,22 @@ public float getTabAnchorCharacterPosition() {
return tabAnchorCharacterPosition;
}
+ /**
+ * Gets a new instance of this class to be used as a next renderer, after this renderer is used, if
+ * {@link #layout(LayoutContext)} is called more than once.
+ *
+ *
+ * If {@link TextRenderer} overflows to the next line, iText uses this method to create a renderer
+ * for the overflow part. So if one wants to extend {@link TextRenderer}, one should override
+ * this method: otherwise the default method will be used and thus the default rather than the custom
+ * renderer will be created. Another method that should be overridden in case of
+ * {@link TextRenderer}'s extension is {@link #createCopy(GlyphLine, PdfFont)}. This method is responsible
+ * for creation of {@link TextRenderer}'s copies, which represent its parts of specific font.
+ * @return new renderer instance
+ */
@Override
public IRenderer getNextRenderer() {
+ logWarningIfGetNextRendererNotOverridden(TextRenderer.class, this.getClass());
return new TextRenderer((Text) modelElement);
}
@@ -1579,7 +1594,24 @@ protected void setProcessedGlyphLineAndFont(GlyphLine gl, PdfFont font) {
setProperty(Property.FONT, font);
}
+ /**
+ * Creates a copy of this {@link TextRenderer}, which corresponds to the passed {@link GlyphLine}
+ * with {@link PdfFont}.
+ *
+ * While processing {@link TextRenderer}, iText uses this method to create {@link GlyphLine glyph lines}
+ * of specific {@link PdfFont fonts}, which represent the {@link TextRenderer}'s parts. If one extends
+ * {@link TextRenderer}, one should override this method, otherwise if {@link com.itextpdf.layout.font.FontSelector}
+ * related logic is triggered, copies of this {@link TextRenderer} will have the default behavior rather than
+ * the custom one.
+ * @param gl a {@link GlyphLine} which represents some of this {@link TextRenderer}'s content
+ * @param font a {@link PdfFont} for this part of the {@link TextRenderer}'s content
+ * @return copy of this {@link TextRenderer}, which correspond to the passed {@link GlyphLine} with {@link PdfFont}
+ */
protected TextRenderer createCopy(GlyphLine gl, PdfFont font) {
+ if (TextRenderer.class != this.getClass()) {
+ Logger logger = LoggerFactory.getLogger(TextRenderer.class);
+ logger.error(MessageFormatUtil.format(LogMessageConstant.CREATE_COPY_SHOULD_BE_OVERRIDDEN));
+ }
TextRenderer copy = new TextRenderer(this);
copy.setProcessedGlyphLineAndFont(gl, font);
return copy;
diff --git a/layout/src/test/java/com/itextpdf/layout/CanvasTest.java b/layout/src/test/java/com/itextpdf/layout/CanvasTest.java
index 92d18796fc..6718dd0a1c 100644
--- a/layout/src/test/java/com/itextpdf/layout/CanvasTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/CanvasTest.java
@@ -62,10 +62,8 @@ This file is part of the iText (R) project.
import java.io.IOException;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class CanvasTest extends ExtendedITextTest {
@@ -78,9 +76,6 @@ public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.UNABLE_TO_APPLY_PAGE_DEPENDENT_PROP_UNKNOWN_PAGE_ON_WHICH_ELEMENT_IS_DRAWN))
public void canvasNoPageLinkTest() throws IOException, InterruptedException {
@@ -254,8 +249,6 @@ public void parentElemWithAbsolPositionKidNotSuitCanvasTest() throws IOException
@Test
//TODO: DEVSIX-4820 (NullPointerException on processing absolutely positioned elements in small canvas area)
public void nestedElementWithAbsolutePositioningInCanvasTest() throws IOException, InterruptedException {
- junitExpectedException.expect(NullPointerException.class);
-
String testName = "nestedElementWithAbsolutePositioningInCanvas";
String out = destinationFolder + testName + ".pdf";
String cmp = sourceFolder + "cmp_" + testName + ".pdf";
@@ -272,8 +265,8 @@ public void nestedElementWithAbsolutePositioningInCanvasTest() throws IOExceptio
divWithPosition.add(new Paragraph("Paragraph in Div with set position"));
notFittingDiv.add(divWithPosition);
- canvas.add(notFittingDiv);
-
+
+ Assert.assertThrows(NullPointerException.class, () -> canvas.add(notFittingDiv));
canvas.close();
}
diff --git a/layout/src/test/java/com/itextpdf/layout/CollapsingMarginsTest.java b/layout/src/test/java/com/itextpdf/layout/CollapsingMarginsTest.java
index f3591f0192..74bbf651f5 100644
--- a/layout/src/test/java/com/itextpdf/layout/CollapsingMarginsTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/CollapsingMarginsTest.java
@@ -63,11 +63,8 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -92,9 +89,6 @@ public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void collapsingMarginsTest01() throws IOException, InterruptedException {
String outFileName = destinationFolder + "collapsingMarginsTest01.pdf";
@@ -343,29 +337,27 @@ private void drawPageBorders(PdfDocument pdfDocument, int pageNum) {
change the type of the expected exception to a more specific one to make the test stricter.
*/
public void columnRendererTest() throws IOException, InterruptedException {
- junitExpectedException.expect(Exception.class);
String outFileName = destinationFolder + "columnRendererTest.pdf";
String cmpFileName = sourceFolder + "cmp_columnRendererTest.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
- Document doc = new Document(pdfDocument);
- doc.setProperty(Property.COLLAPSING_MARGINS, true);
+ try (Document doc = new Document(pdfDocument)) {
+ doc.setProperty(Property.COLLAPSING_MARGINS, true);
- Paragraph p = new Paragraph();
- for (int i = 0; i < 10; i++) {
- p.add(TEXT_BYRON);
- }
-
- Div div = new Div().add(p);
- List areas = new ArrayList<>();
- areas.add(new Rectangle(30, 30, 150, 600));
- areas.add(new Rectangle(200, 30, 150, 600));
- areas.add(new Rectangle(370, 30, 150, 600));
- div.setNextRenderer(new CustomColumnDocumentRenderer(div, areas));
+ Paragraph p = new Paragraph();
+ for (int i = 0; i < 10; i++) {
+ p.add(TEXT_BYRON);
+ }
- doc.add(div);
+ Div div = new Div().add(p);
+ List areas = new ArrayList<>();
+ areas.add(new Rectangle(30, 30, 150, 600));
+ areas.add(new Rectangle(200, 30, 150, 600));
+ areas.add(new Rectangle(370, 30, 150, 600));
+ div.setNextRenderer(new CustomColumnDocumentRenderer(div, areas));
- doc.close();
+ Assert.assertThrows(Exception.class, () -> doc.add(div));
+ }
Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
}
diff --git a/layout/src/test/java/com/itextpdf/layout/FontProviderTest.java b/layout/src/test/java/com/itextpdf/layout/FontProviderTest.java
index b0e5eed52e..589ba9dfb3 100644
--- a/layout/src/test/java/com/itextpdf/layout/FontProviderTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/FontProviderTest.java
@@ -64,10 +64,8 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -78,9 +76,6 @@ This file is part of the iText (R) project.
@Category(IntegrationTest.class)
public class FontProviderTest extends ExtendedITextTest {
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
private static class PdfFontProvider extends FontProvider {
private List pdfFontInfos = new ArrayList<>();
@@ -202,20 +197,17 @@ public void customFontProvider2() throws Exception {
@Test
public void fontProviderNotSetExceptionTest() throws Exception {
- junitExpectedException.expect(IllegalStateException.class);
- junitExpectedException.expectMessage(PdfException.FontProviderNotSetFontFamilyNotResolved);
-
String fileName = "fontProviderNotSetExceptionTest.pdf";
String outFileName = destinationFolder + fileName + ".pdf";
- PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)));
- Document doc = new Document(pdfDoc);
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new FileOutputStream(outFileName)))) {
+ Document doc = new Document(pdfDoc);
- Paragraph paragraph = new Paragraph("Hello world!")
- .setFontFamily("ABRACADABRA_NO_FONT_PROVIDER_ANYWAY");
- doc.add(paragraph);
+ Paragraph paragraph = new Paragraph("Hello world!")
+ .setFontFamily("ABRACADABRA_NO_FONT_PROVIDER_ANYWAY");
- doc.close();
+ Exception e = Assert.assertThrows(IllegalStateException.class, () -> doc.add(paragraph));
+ Assert.assertEquals(PdfException.FontProviderNotSetFontFamilyNotResolved, e.getMessage());
+ }
}
-
}
diff --git a/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java b/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java
index b81b28b7cf..304a32f7f1 100644
--- a/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/FontSelectorTest.java
@@ -563,7 +563,95 @@ public void standardFontSetCourierTest01() {
public void openSansFontSetIncorrectNameTest01() {
FontSet set = getOpenSansFontSet();
addTimesFonts(set);
- checkSelector(set.getFonts(), "OpenSans", "OpenSans-Light", "OpenSans-Bold", "OpenSans-LightItalic", "OpenSans-BoldItalic");
+ Collection fontInfoCollection = set.getFonts();
+ List fontFamilies = new ArrayList<>();
+ fontFamilies.add("Open Sans");
+
+ // Normal
+
+ FontCharacteristics fc = new FontCharacteristics();
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 100);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ // Bold
+
+ fc = new FontCharacteristics();
+ fc.setBoldFlag(true);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-SemiBold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBold");
+
+ // Italic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 500);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ // BoldItalic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBoldItalic");
}
@Test
@@ -572,7 +660,95 @@ public void openSansFontSetIncorrectNameTest01() {
public void openSansFontSetRegularTest01() {
FontSet set = getOpenSansFontSet();
addTimesFonts(set);
- checkSelector(set.getFonts(), "Open Sans", "OpenSans-Light", "OpenSans-Bold", "OpenSans-LightItalic", "OpenSans-BoldItalic");
+ Collection fontInfoCollection = set.getFonts();
+ List fontFamilies = new ArrayList<>();
+ fontFamilies.add("Open Sans");
+
+ // Normal
+
+ FontCharacteristics fc = new FontCharacteristics();
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 100);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ // Bold
+
+ fc = new FontCharacteristics();
+ fc.setBoldFlag(true);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-SemiBold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBold");
+
+ // Italic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 500);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ // BoldItalic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBoldItalic");
}
@Test
@@ -582,7 +758,95 @@ public void openSansFontSetRegularTest01() {
public void openSansFontSetLightTest01() {
FontSet set = getOpenSansFontSet();
addTimesFonts(set);
- checkSelector(set.getFonts(), "Open Sans Light", "OpenSans-Light", "OpenSans-Bold", "OpenSans-LightItalic", "OpenSans-BoldItalic");
+ Collection fontInfoCollection = set.getFonts();
+ List fontFamilies = new ArrayList<>();
+ fontFamilies.add("Open Sans");
+
+ // Normal
+
+ FontCharacteristics fc = new FontCharacteristics();
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 100);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ // Bold
+
+ fc = new FontCharacteristics();
+ fc.setBoldFlag(true);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-SemiBold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBold");
+
+ // Italic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 500);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ // BoldItalic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBoldItalic");
}
@Test
@@ -592,11 +856,98 @@ public void openSansFontSetLightTest01() {
public void openSansFontSetExtraBoldTest01() {
FontSet set = getOpenSansFontSet();
addTimesFonts(set);
- checkSelector(set.getFonts(), "Open Sans ExtraBold", "Times-Bold", "Times-Bold", "Times-BoldItalic", "Times-BoldItalic");
+ Collection fontInfoCollection = set.getFonts();
+ List fontFamilies = new ArrayList<>();
+ fontFamilies.add("Open Sans");
+
+ // Normal
+
+ FontCharacteristics fc = new FontCharacteristics();
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 100);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Light");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Regular");
+
+ // Bold
+
+ fc = new FontCharacteristics();
+ fc.setBoldFlag(true);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-SemiBold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Bold");
+
+ fc = new FontCharacteristics();
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBold");
+
+ // Italic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("normal");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 300);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 500);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-LightItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-Italic");
+
+ // BoldItalic
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("oblique");
+ fc.setFontWeight("bold");
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 700);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-BoldItalic");
+
+ fc = new FontCharacteristics();
+ fc.setFontStyle("italic");
+ fc.setFontWeight((short) 800);
+ assertSelectedFont(fontInfoCollection, fontFamilies, fc, "OpenSans-ExtraBoldItalic");
}
@Test
- //TODO: DEVSIX-4147 (update cmp-file after the issue will be resolved)
public void openSansFontWeightBoldRenderingTest() throws Exception {
String outFileName = destinationFolder + "openSansFontWeightBoldRendering.pdf";
String cmpFileName = sourceFolder + "cmp_openSansFontWeightBoldRendering.pdf";
@@ -633,7 +984,6 @@ public void openSansFontWeightBoldRenderingTest() throws Exception {
}
@Test
- //TODO: DEVSIX-4147 (update cmp-file after the issue will be resolved)
public void openSansFontWeightNotBoldRenderingTest() throws Exception {
String outFileName = destinationFolder + "openSansFontWeightNotBoldRendering.pdf";
String cmpFileName = sourceFolder + "cmp_openSansFontWeightNotBoldRendering.pdf";
diff --git a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java
index 1b5825a579..7d2d763aaa 100644
--- a/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java
+++ b/layout/src/test/java/com/itextpdf/layout/LayoutTaggingPdf2Test.java
@@ -71,12 +71,11 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
@@ -91,9 +90,6 @@ public class LayoutTaggingPdf2Test extends ExtendedITextTest {
public static final String imageName = "Desert.jpg";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/layout/LayoutTaggingPdf2Test/";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
@@ -327,9 +323,6 @@ public void docWithExplicitAndImplicitDefaultNsAtTheSameTime() throws IOExceptio
@Test
public void docWithInvalidMapping01() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole, "p", "http://iso.org/pdf/ssn"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping01.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0)));
pdfDocument.setTagged();
@@ -337,25 +330,24 @@ public void docWithInvalidMapping01() throws IOException {
tagsContext.setDocumentDefaultNamespace(null);
PdfNamespace explicitDefaultNs = tagsContext.fetchNamespace(StandardNamespaces.PDF_1_7);
- Document document = new Document(pdfDocument);
+ try (Document document = new Document(pdfDocument)) {
- pdfDocument.getStructTreeRoot().addRoleMapping(HtmlRoles.p, StandardRoles.P);
-
- Paragraph customRolePara = new Paragraph("Hello world text.");
- customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- customRolePara.getAccessibilityProperties().setNamespace(explicitDefaultNs);
- document.add(customRolePara);
+ pdfDocument.getStructTreeRoot().addRoleMapping(HtmlRoles.p, StandardRoles.P);
- document.close();
+ Paragraph customRolePara = new Paragraph("Hello world text.");
+ customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
+ customRolePara.getAccessibilityProperties().setNamespace(explicitDefaultNs);
- // compareResult("docWithInvalidMapping01");
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> document.add(customRolePara)
+ );
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole,
+ "p", "http://iso.org/pdf/ssn"), e.getMessage());
+ }
}
@Test
public void docWithInvalidMapping02() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleIsNotMappedToAnyStandardRole, "p"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping02.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0)));
pdfDocument.setTagged();
@@ -363,37 +355,36 @@ public void docWithInvalidMapping02() throws IOException {
tagsContext.setDocumentDefaultNamespace(null);
PdfNamespace explicitDefaultNs = tagsContext.fetchNamespace(StandardNamespaces.PDF_1_7);
- Document document = new Document(pdfDocument);
-
- explicitDefaultNs.addNamespaceRoleMapping(HtmlRoles.p, StandardRoles.P);
+ try (Document document = new Document(pdfDocument)) {
- Paragraph customRolePara = new Paragraph("Hello world text.");
- customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- document.add(customRolePara);
+ explicitDefaultNs.addNamespaceRoleMapping(HtmlRoles.p, StandardRoles.P);
- document.close();
+ Paragraph customRolePara = new Paragraph("Hello world text.");
+ customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- // compareResult("docWithInvalidMapping02");
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> document.add(customRolePara)
+ );
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleIsNotMappedToAnyStandardRole, "p"),
+ e.getMessage());
+ }
}
@Test
public void docWithInvalidMapping03() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole, "p", "http://iso.org/pdf2/ssn"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping03.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0)));
pdfDocument.setTagged();
- Document document = new Document(pdfDocument);
-
- Paragraph customRolePara = new Paragraph("Hello world text.");
- customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- document.add(customRolePara);
+ try (Document document = new Document(pdfDocument)) {
- document.close();
+ Paragraph customRolePara = new Paragraph("Hello world text.");
+ customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- // compareResult("docWithInvalidMapping03");
+ Exception e = Assert.assertThrows(PdfException.class, () -> document.add(customRolePara));
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole,
+ "p", "http://iso.org/pdf2/ssn"), e.getMessage());
+ }
}
@Test
@@ -422,33 +413,29 @@ public void docWithInvalidMapping04() throws IOException, InterruptedException,
@Test
public void docWithInvalidMapping05() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole, "p", "http://iso.org/pdf2/ssn"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping05.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0)));
pdfDocument.setTagged();
- Document document = new Document(pdfDocument);
+ try (Document document = new Document(pdfDocument)) {
- // deliberately creating namespace via constructor instead of using TagStructureContext#fetchNamespace
- PdfNamespace stdNs2 = new PdfNamespace(StandardNamespaces.PDF_2_0);
- stdNs2.addNamespaceRoleMapping(HtmlRoles.p, StandardRoles.P, stdNs2);
-
- Paragraph customRolePara = new Paragraph("Hello world text.");
- customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
- customRolePara.getAccessibilityProperties().setNamespace(stdNs2);
- document.add(customRolePara);
-
- Paragraph customRolePara2 = new Paragraph("Hello world text.");
- customRolePara2.getAccessibilityProperties().setRole(HtmlRoles.p);
- // not explicitly setting namespace that we've manually created. This will lead to the situation, when
- // /Namespaces entry in StructTreeRoot would have two different namespace dictionaries with the same name.
- document.add(customRolePara2);
+ // deliberately creating namespace via constructor instead of using TagStructureContext#fetchNamespace
+ PdfNamespace stdNs2 = new PdfNamespace(StandardNamespaces.PDF_2_0);
+ stdNs2.addNamespaceRoleMapping(HtmlRoles.p, StandardRoles.P, stdNs2);
- document.close();
+ Paragraph customRolePara = new Paragraph("Hello world text.");
+ customRolePara.getAccessibilityProperties().setRole(HtmlRoles.p);
+ customRolePara.getAccessibilityProperties().setNamespace(stdNs2);
+ document.add(customRolePara);
-// compareResult("docWithInvalidMapping05");
+ Paragraph customRolePara2 = new Paragraph("Hello world text.");
+ customRolePara2.getAccessibilityProperties().setRole(HtmlRoles.p);
+ // not explicitly setting namespace that we've manually created. This will lead to the situation, when
+ // /Namespaces entry in StructTreeRoot would have two different namespace dictionaries with the same name.
+ Exception e = Assert.assertThrows(PdfException.class, () -> document.add(customRolePara2));
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole,
+ "p", "http://iso.org/pdf2/ssn"), e.getMessage());
+ }
}
@Test
@@ -488,54 +475,46 @@ public void docWithInvalidMapping06() throws IOException, InterruptedException,
@Test
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.CANNOT_RESOLVE_ROLE_IN_NAMESPACE_TOO_MUCH_TRANSITIVE_MAPPINGS, count = 1))
public void docWithInvalidMapping07() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole, "span", "http://iso.org/pdf2/ssn"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping07.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_2_0)));
pdfDocument.setTagged();
- Document document = new Document(pdfDocument);
+ try (Document document = new Document(pdfDocument)) {
- PdfNamespace stdNs2 = pdfDocument.getTagStructureContext().fetchNamespace(StandardNamespaces.PDF_2_0);
- int numOfTransitiveMappings = 120;
- String prevRole = HtmlRoles.span;
- for (int i = 0; i < numOfTransitiveMappings; ++i) {
- String nextRole = "span" + i;
- stdNs2.addNamespaceRoleMapping(prevRole, nextRole, stdNs2);
- prevRole = nextRole;
- }
- stdNs2.addNamespaceRoleMapping(prevRole, StandardRoles.SPAN, stdNs2);
-
-
- Text customRolePText1 = new Text("Hello world text.");
- customRolePText1.getAccessibilityProperties().setRole(HtmlRoles.span);
- customRolePText1.getAccessibilityProperties().setNamespace(stdNs2);
- document.add(new Paragraph(customRolePText1));
+ PdfNamespace stdNs2 = pdfDocument.getTagStructureContext().fetchNamespace(StandardNamespaces.PDF_2_0);
+ int numOfTransitiveMappings = 120;
+ String prevRole = HtmlRoles.span;
+ for (int i = 0; i < numOfTransitiveMappings; ++i) {
+ String nextRole = "span" + i;
+ stdNs2.addNamespaceRoleMapping(prevRole, nextRole, stdNs2);
+ prevRole = nextRole;
+ }
+ stdNs2.addNamespaceRoleMapping(prevRole, StandardRoles.SPAN, stdNs2);
- document.close();
+ Text customRolePText1 = new Text("Hello world text.");
+ customRolePText1.getAccessibilityProperties().setRole(HtmlRoles.span);
+ customRolePText1.getAccessibilityProperties().setNamespace(stdNs2);
-// compareResult("docWithInvalidMapping07");
+ Exception e = Assert.assertThrows(PdfException.class, () -> document.add(new Paragraph(customRolePText1)));
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleInNamespaceIsNotMappedToAnyStandardRole,
+ "span", "http://iso.org/pdf2/ssn"), e.getMessage());
+ }
}
@Test
public void docWithInvalidMapping08() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(MessageFormat.format(PdfException.RoleIsNotMappedToAnyStandardRole, "H9"));
-
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destinationFolder + "docWithInvalidMapping08.pdf",
new WriterProperties().setPdfVersion(PdfVersion.PDF_1_7)));
pdfDocument.setTagged();
- Document document = new Document(pdfDocument);
-
- Paragraph h9Para = new Paragraph("Header level 9");
- h9Para.getAccessibilityProperties().setRole("H9");
- document.add(h9Para);
+ try (Document document = new Document(pdfDocument)) {
- document.close();
+ Paragraph h9Para = new Paragraph("Header level 9");
+ h9Para.getAccessibilityProperties().setRole("H9");
-// compareResult("docWithInvalidMapping08");
+ Exception e = Assert.assertThrows(PdfException.class, () -> document.add(h9Para));
+ Assert.assertEquals(MessageFormat.format(PdfException.RoleIsNotMappedToAnyStandardRole, "H9"), e.getMessage());
+ }
}
@Test
diff --git a/layout/src/test/java/com/itextpdf/layout/LinkTest.java b/layout/src/test/java/com/itextpdf/layout/LinkTest.java
index f9d38a1db7..31f9a4449e 100644
--- a/layout/src/test/java/com/itextpdf/layout/LinkTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/LinkTest.java
@@ -70,13 +70,11 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.FileOutputStream;
import java.io.IOException;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class LinkTest extends ExtendedITextTest {
@@ -91,9 +89,6 @@ public class LinkTest extends ExtendedITextTest {
+ "Donec fringilla sapien sed neque finibus, non luctus justo lobortis. Praesent commodo pellentesque ligula, vel fringilla odio commodo id. Nam ultrices justo a dignissim congue. Nullam imperdiet sem eget placerat aliquam. Suspendisse non faucibus libero. Aenean purus arcu, auctor vitae tincidunt in, tincidunt at ante. Pellentesque euismod, velit vel vulputate faucibus, dolor erat consectetur sapien, ut elementum dui turpis nec lacus. In hac habitasse platea dictumst. Aenean vel elit ultrices, varius mi quis, congue erat."
+ "Curabitur sit amet nunc porttitor, congue elit vestibulum, vestibulum sapien. Fusce ut arcu consequat, scelerisque sapien vitae, dignissim ligula. Duis gravida mollis volutpat. Maecenas condimentum pulvinar urna in cursus. Nulla ornare est non tellus elementum auctor. Mauris ornare, elit non ornare lobortis, risus augue consectetur orci, ac efficitur ex nunc nec leo. Aenean dictum mattis magna vitae bibendum.";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createDestinationFolder(destinationFolder);
diff --git a/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java b/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java
index 4dcd11c336..729d5fd05f 100644
--- a/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/OrphansWidowsTest.java
@@ -559,6 +559,11 @@ private static class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer(CustomParagraph modelElement) {
super(modelElement);
}
+
+ @Override
+ public IRenderer getNextRenderer() {
+ return new CustomParagraphRenderer((CustomParagraph) this.modelElement);
+ }
}
private static class CustomParagraph extends Paragraph {
diff --git a/layout/src/test/java/com/itextpdf/layout/PositioningTest.java b/layout/src/test/java/com/itextpdf/layout/PositioningTest.java
index 8fd88722c6..03df1c6d72 100644
--- a/layout/src/test/java/com/itextpdf/layout/PositioningTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/PositioningTest.java
@@ -69,12 +69,11 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.junit.Assert;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.IOException;
@@ -89,9 +88,6 @@ public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void relativePositioningTest01() throws IOException, InterruptedException {
String outFileName = destinationFolder + "relativePositioningTest01.pdf";
@@ -367,25 +363,26 @@ public void showTextAlignedTest03() throws IOException, InterruptedException {
@Test
public void showTextAlignedOnFlushedPageTest01() throws IOException {
- junitExpectedException.expect(PdfException.class);
- junitExpectedException.expectMessage(PdfException.CannotDrawElementsOnAlreadyFlushedPages);
-
String outFileName = destinationFolder + "showTextAlignedOnFlushedPageTest01.pdf";
- PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
- Document doc = new Document(pdfDoc);
+ try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
+ Document doc = new Document(pdfDoc)) {
- Paragraph p = new Paragraph();
- for (int i = 0; i < 1000; ++i) {
- p.add("abcdefghijklkmnopqrstuvwxyz");
- }
+ Paragraph p = new Paragraph();
+ for (int i = 0; i < 1000; ++i) {
+ p.add("abcdefghijklkmnopqrstuvwxyz");
+ }
- doc.add(p);
- // First page will be flushed by now, because immediateFlush is set to false by default.
- int pageNumberToDrawTextOn = 1;
- doc.showTextAligned(new Paragraph("Hello Bruno on page 1!"), 36, 36, pageNumberToDrawTextOn, TextAlignment.LEFT, VerticalAlignment.TOP, 0);
+ doc.add(p);
+ // First page will be flushed by now, because immediateFlush is set to false by default.
+ int pageNumberToDrawTextOn = 1;
- doc.close();
+ Exception e = Assert.assertThrows(PdfException.class,
+ () -> doc.showTextAligned(new Paragraph("Hello Bruno on page 1!"), 36, 36, pageNumberToDrawTextOn,
+ TextAlignment.LEFT, VerticalAlignment.TOP, 0)
+ );
+ Assert.assertEquals(PdfException.CannotDrawElementsOnAlreadyFlushedPages, e.getMessage());
+ }
}
diff --git a/layout/src/test/java/com/itextpdf/layout/StylesTest.java b/layout/src/test/java/com/itextpdf/layout/StylesTest.java
index fd1b821290..37baa21e1c 100644
--- a/layout/src/test/java/com/itextpdf/layout/StylesTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/StylesTest.java
@@ -52,19 +52,14 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.type.IntegrationTest;
import org.junit.Assert;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class StylesTest extends ExtendedITextTest {
public static float EPS = 0.0001f;
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@Test
public void copyConstructorTest() {
Style myStyle = new Style();
@@ -133,18 +128,9 @@ public void addingSeveralStyleTest() {
@Test
public void addNullAsStyleTest() {
- // Sharpen mappings map NPE to NullReferenceException, however in .NET in this situation
- // ArgumentNullException is thrown. In order not to introduce any porting issues,
- // which unfortunately couldn't be handled in a convenient way, the most basic Exception
- // is set to be expected.
- junitExpectedException.expect(Exception.class);
-
- Style myStyle = null;
-
- Paragraph p = new Paragraph("text").addStyle(myStyle);
+ Paragraph p = new Paragraph("text");
- // the following line should produce a NPE
- p.getRenderer().getProperty(Property.FONT_COLOR);
+ Assert.assertThrows(IllegalArgumentException.class, () -> p.addStyle(null));
}
@Test
diff --git a/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java b/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java
index e50a5418bb..e596482121 100644
--- a/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/TableBorderTest.java
@@ -67,13 +67,11 @@ This file is part of the iText (R) project.
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.FileNotFoundException;
import java.io.IOException;
-import org.junit.rules.ExpectedException;
@Category(IntegrationTest.class)
public class TableBorderTest extends ExtendedITextTest {
@@ -81,9 +79,6 @@ public class TableBorderTest extends ExtendedITextTest {
public static final String destinationFolder = "./target/test/com/itextpdf/layout/TableBorderTest/";
public static final String cmpPrefix = "cmp_";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
String fileName;
String outFileName;
String cmpFileName;
diff --git a/layout/src/test/java/com/itextpdf/layout/TableTest.java b/layout/src/test/java/com/itextpdf/layout/TableTest.java
index fbbdf34f9c..6e0ca81f42 100644
--- a/layout/src/test/java/com/itextpdf/layout/TableTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/TableTest.java
@@ -80,13 +80,12 @@ This file is part of the iText (R) project.
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import com.itextpdf.test.annotations.type.IntegrationTest;
+
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -103,9 +102,6 @@ public class TableTest extends ExtendedITextTest {
private static final String MIDDLE_TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.\n" +
"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.";
- @Rule
- public ExpectedException junitExpectedException = ExpectedException.none();
-
@BeforeClass
public static void beforeClass() {
createDestinationFolder(destinationFolder);
@@ -1825,7 +1821,9 @@ public void tableWithIncompleteFooter() throws IOException, InterruptedException
}
@Test
- @LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.LAST_ROW_IS_NOT_COMPLETE, count = 1)})
+ @LogMessages(messages = {
+ @LogMessage(messageTemplate = LogMessageConstant.LAST_ROW_IS_NOT_COMPLETE),
+ @LogMessage(messageTemplate = LogMessageConstant.GET_NEXT_RENDERER_SHOULD_BE_OVERRIDDEN)})
public void tableWithCustomRendererTest01() throws IOException, InterruptedException {
String testName = "tableWithCustomRendererTest01.pdf";
String outFileName = destinationFolder + testName;
@@ -3046,6 +3044,117 @@ public void inheritHeaderPropsWhileMinMaxWidthCalculationsTest() throws IOExcept
sourceFolder + "cmp_" + filename, destinationFolder, "diff"));
}
+ @Test
+ // TODO DEVSIX-5250 The first column should be fully red
+ public void bigRowSpanTooFarFullTest() throws IOException, InterruptedException {
+ String filename = "bigRowSpanTooFarFullTest.pdf";
+
+ PdfDocument pdf = new PdfDocument(new PdfWriter(destinationFolder + filename));
+ Document document = new Document(pdf);
+
+ Table table = new Table(2);
+
+ int bigRowSpan = 5;
+ table.addCell(
+ new Cell(bigRowSpan, 1)
+ .add(new Paragraph("row span " + bigRowSpan))
+ .setBackgroundColor(ColorConstants.RED));
+ for (int i = 0; i < bigRowSpan; i++) {
+ table.addCell(
+ new Cell()
+ .add(new Paragraph(Integer.toString(i)))
+ .setHeight(375)
+ .setBackgroundColor(ColorConstants.BLUE));
+ }
+
+ document.add(table);
+ document.add(new AreaBreak());
+
+ table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
+ document.add(table);
+
+ document.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename,
+ sourceFolder + "cmp_" + filename, destinationFolder));
+ }
+
+ @Test
+ // TODO DEVSIX-5250 The first column should be fully red, but on page 2 it is not
+ public void bigRowSpanTooFarPartialTest() throws IOException, InterruptedException {
+ String filename = "bigRowSpanTooFarPartialTest.pdf";
+
+ PdfDocument pdf = new PdfDocument(new PdfWriter(destinationFolder + filename));
+ Document document = new Document(pdf);
+
+ Table table = new Table(2);
+
+ int bigRowSpan = 5;
+ table.addCell(
+ new Cell(bigRowSpan, 1)
+ .add(new Paragraph("row span " + bigRowSpan))
+ .setHeight(800)
+ .setBackgroundColor(ColorConstants.RED));
+ for (int i = 0; i < bigRowSpan; i++) {
+ table.addCell(
+ new Cell()
+ .add(new Paragraph(Integer.toString(i)))
+ .setHeight(375)
+ .setBackgroundColor(ColorConstants.BLUE));
+ }
+
+ document.add(table);
+ document.add(new AreaBreak());
+
+ table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
+ document.add(table);
+
+ document.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename,
+ sourceFolder + "cmp_" + filename, destinationFolder));
+ }
+
+ @Test
+ @LogMessages(messages = {
+ @LogMessage(messageTemplate = LogMessageConstant.ELEMENT_DOES_NOT_FIT_AREA, count = 1)
+ })
+ // TODO DEVSIX-5250 The first column should be fully red
+ public void bigRowSpanTooFarNothingTest() throws IOException, InterruptedException {
+ String filename = "bigRowSpanTooFarNothingTest.pdf";
+
+ PdfDocument pdf = new PdfDocument(new PdfWriter(destinationFolder + filename));
+ Document document = new Document(pdf);
+
+ Table table = new Table(2);
+
+ int bigRowSpan = 5;
+ table.addCell(
+ new Cell(bigRowSpan, 1)
+ .add(new Paragraph("row span " + bigRowSpan))
+ .setHeight(800)
+ .setKeepTogether(true)
+ .setBackgroundColor(ColorConstants.RED));
+ for (int i = 0; i < bigRowSpan; i++) {
+ table.addCell(
+ new Cell()
+ .add(new Paragraph(Integer.toString(i)))
+ .setHeight(375)
+ .setBackgroundColor(ColorConstants.BLUE));
+ }
+
+ document.add(table);
+ document.add(new AreaBreak());
+
+ table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
+ document.add(table);
+
+ document.close();
+
+ Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename,
+ sourceFolder + "cmp_" + filename, destinationFolder));
+ }
+
private static class RotatedDocumentRenderer extends DocumentRenderer {
private final PdfDocument pdfDoc;
diff --git a/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java b/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java
index 4de1b231f8..cdce458a9e 100644
--- a/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java
+++ b/layout/src/test/java/com/itextpdf/layout/element/FlexContainerTest.java
@@ -80,14 +80,9 @@ public FlexContainerTest(Object alignItemsValue, Object justifyContentValue, Obj
public static Iterable