diff --git a/README.md b/README.md index bec8eef932..f5f7a71f56 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ iText is licensed as [AGPL][agpl] software. AGPL is a free / open source software license. -This doesn't mean the software is gratis! +This doesn't mean the software is [gratis][gratis]! Buying a license is mandatory as soon as you develop commercial activities distributing the iText software inside your product or deploying it on a network @@ -41,3 +41,4 @@ Contact sales for more info: http://itextpdf.com/sales [contributing]: CONTRIBUTING.md [extrajars]: EXTRAJARS.md [itext]: http://itextpdf.com/ +[gratis]: https://en.wikipedia.org/wiki/Gratis_versus_libre diff --git a/itext/barcodeDataMatrix.pdf b/itext/barcodeDataMatrix.pdf new file mode 100644 index 0000000000..4fadc31abc Binary files /dev/null and b/itext/barcodeDataMatrix.pdf differ diff --git a/itext/pom.xml b/itext/pom.xml index ecf6aee9b5..f3b6c82bc2 100644 --- a/itext/pom.xml +++ b/itext/pom.xml @@ -10,7 +10,7 @@ itextpdf - 5.5.11 + 5.5.12 iText Core A Free Java-PDF library @@ -268,18 +268,6 @@ http://developers.itextpdf.com/reference/classes - diff --git a/itext/src/main/java/com/itextpdf/awt/PdfGraphics2D.java b/itext/src/main/java/com/itextpdf/awt/PdfGraphics2D.java index 42540f217c..321a499206 100644 --- a/itext/src/main/java/com/itextpdf/awt/PdfGraphics2D.java +++ b/itext/src/main/java/com/itextpdf/awt/PdfGraphics2D.java @@ -202,14 +202,15 @@ private static final class Kid { private Graphics2D getDG2() { if (dg2 == null) { dg2 = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB).createGraphics(); - dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); + dg2.setRenderingHints(rhints); } return dg2; } - private PdfGraphics2D() {} + private PdfGraphics2D() { + setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); + } public PdfGraphics2D(PdfContentByte cb, final float width, final float height) { this(cb, width, height, null, false, false, 0); @@ -507,21 +508,32 @@ public void drawString(String s, float x, float y) { double width = 0; if (font.getSize2D() > 0) { - float scale = 1000 / font.getSize2D(); - Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); - width = derivedFont.getStringBounds(s, getFontRenderContext()).getWidth(); - if (derivedFont.isTransformed()) - width /= scale; + if (RenderingHints.VALUE_FRACTIONALMETRICS_OFF.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS))) { + width = font.getStringBounds(s, getFontRenderContext()).getWidth(); + } else { + float scale = 1000 / font.getSize2D(); + Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); + width = derivedFont.getStringBounds(s, getFontRenderContext()).getWidth(); + if (derivedFont.isTransformed()) + width /= scale; + } } // if the hyperlink flag is set add an action to the text Object url = getRenderingHint(HyperLinkKey.KEY_INSTANCE); if (url != null && !url.equals(HyperLinkKey.VALUE_HYPERLINKKEY_OFF)) { - float scale = 1000 / font.getSize2D(); - Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); - double height = derivedFont.getStringBounds(s, getFontRenderContext()).getHeight(); - if (derivedFont.isTransformed()) - height /= scale; + double height = 0; + if (font.getSize2D() > 0) { + if (RenderingHints.VALUE_FRACTIONALMETRICS_OFF.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS))) { + height = font.getStringBounds(s, getFontRenderContext()).getHeight(); + } else { + float scale = 1000 / font.getSize2D(); + Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); + height = derivedFont.getStringBounds(s, getFontRenderContext()).getHeight(); + if (derivedFont.isTransformed()) + height /= scale; + } + } double leftX = cb.getXTLM(); double leftY = cb.getYTLM(); PdfAction action = new PdfAction(url.toString()); @@ -817,32 +829,33 @@ public void setStroke(Stroke s) { /** * Sets a rendering hint - * @param arg0 - * @param arg1 + * @param hintKey + * @param hintValue */ @Override - public void setRenderingHint(Key arg0, Object arg1) { - if (arg1 != null) { - rhints.put(arg0, arg1); + public void setRenderingHint(Key hintKey, Object hintValue) { + if (hintValue != null) { + rhints.put(hintKey, hintValue); } else { - if (arg0 instanceof HyperLinkKey) - { - rhints.put(arg0, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); + if (hintKey instanceof HyperLinkKey) { + rhints.put(hintKey, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); } - else - { - rhints.remove(arg0); + else { + rhints.remove(hintKey); } } + if (dg2 != null) { + dg2.setRenderingHint(hintKey, hintValue); + } } /** - * @param arg0 a key + * @param hintKey a key * @return the rendering hint */ @Override - public Object getRenderingHint(Key arg0) { - return rhints.get(arg0); + public Object getRenderingHint(Key hintKey) { + return rhints.get(hintKey); } /** @@ -852,6 +865,9 @@ public Object getRenderingHint(Key arg0) { public void setRenderingHints(Map hints) { rhints.clear(); rhints.putAll(hints); + if (dg2 != null) { + dg2.setRenderingHints(hints); + } } /** @@ -860,6 +876,9 @@ public void setRenderingHints(Map hints) { @Override public void addRenderingHints(Map hints) { rhints.putAll(hints); + if (dg2 != null) { + dg2.addRenderingHints(hints); + } } /** diff --git a/itext/src/main/java/com/itextpdf/testutils/CompareTool.java b/itext/src/main/java/com/itextpdf/testutils/CompareTool.java index 4d982ccd5c..ca688a8161 100644 --- a/itext/src/main/java/com/itextpdf/testutils/CompareTool.java +++ b/itext/src/main/java/com/itextpdf/testutils/CompareTool.java @@ -79,6 +79,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -91,6 +92,7 @@ import java.util.StringTokenizer; import java.util.TreeSet; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -104,6 +106,8 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** @@ -375,6 +379,9 @@ public void writeReportToXml(OutputStream stream) throws ParserConfigurationExce xmlReport.appendChild(root); TransformerFactory tFactory = TransformerFactory.newInstance(); + try { + tFactory.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (Exception exc) {} Transformer transformer = tFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(xmlReport); @@ -1193,6 +1200,7 @@ public boolean compareXmls(byte[] xml1, byte[] xml2) throws ParserConfigurationE dbf.setIgnoringElementContentWhitespace(true); dbf.setIgnoringComments(true); DocumentBuilder db = dbf.newDocumentBuilder(); + db.setEntityResolver(new SafeEmptyEntityResolver()); org.w3c.dom.Document doc1 = db.parse(new ByteArrayInputStream(xml1)); doc1.normalizeDocument(); @@ -1343,6 +1351,7 @@ public boolean compareXmls(String xml1, String xml2) throws ParserConfigurationE dbf.setIgnoringElementContentWhitespace(true); dbf.setIgnoringComments(true); DocumentBuilder db = dbf.newDocumentBuilder(); + db.setEntityResolver(new SafeEmptyEntityResolver()); org.w3c.dom.Document doc1 = db.parse(new File(xml1)); doc1.normalizeDocument(); @@ -1486,5 +1495,11 @@ public void renderImage(ImageRenderInfo renderInfo) { } + private static class SafeEmptyEntityResolver implements EntityResolver { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + } + } diff --git a/itext/src/main/java/com/itextpdf/text/Version.java b/itext/src/main/java/com/itextpdf/text/Version.java index ae5a984c7c..5d14310115 100644 --- a/itext/src/main/java/com/itextpdf/text/Version.java +++ b/itext/src/main/java/com/itextpdf/text/Version.java @@ -70,7 +70,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 String release = "5.5.11"; + private String release = "5.5.12"; /** * This String contains the iText version as shown in the producer line. * iText is a product developed by iText Group NV. diff --git a/itext/src/main/java/com/itextpdf/text/pdf/BarcodeDatamatrix.java b/itext/src/main/java/com/itextpdf/text/pdf/BarcodeDatamatrix.java index 3b7155b380..fc1be9ed04 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/BarcodeDatamatrix.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/BarcodeDatamatrix.java @@ -94,8 +94,15 @@ public class BarcodeDatamatrix { */ public static final int DM_B256 = 4; /** - * X21 encodation. + * X12 encodation. */ + public static final int DM_X12 = 5; + /** + * X12 encodation. + * + * @deprecated Use {@link BarcodeDataMatrix#DM_X12} instead. + */ + @Deprecated public static final int DM_X21 = 5; /** * EDIFACT encodation. @@ -115,39 +122,59 @@ public class BarcodeDatamatrix { */ public static final int DM_TEST = 64; - private final static DmParams[] dmSizes = { - new DmParams(10, 10, 10, 10, 3, 3, 5), - new DmParams(12, 12, 12, 12, 5, 5, 7), - new DmParams(8, 18, 8, 18, 5, 5, 7), - new DmParams(14, 14, 14, 14, 8, 8, 10), - new DmParams(8, 32, 8, 16, 10, 10, 11), - new DmParams(16, 16, 16, 16, 12, 12, 12), - new DmParams(12, 26, 12, 26, 16, 16, 14), - new DmParams(18, 18, 18, 18, 18, 18, 14), - new DmParams(20, 20, 20, 20, 22, 22, 18), - new DmParams(12, 36, 12, 18, 22, 22, 18), - new DmParams(22, 22, 22, 22, 30, 30, 20), - new DmParams(16, 36, 16, 18, 32, 32, 24), - new DmParams(24, 24, 24, 24, 36, 36, 24), - new DmParams(26, 26, 26, 26, 44, 44, 28), - new DmParams(16, 48, 16, 24, 49, 49, 28), - new DmParams(32, 32, 16, 16, 62, 62, 36), - new DmParams(36, 36, 18, 18, 86, 86, 42), - new DmParams(40, 40, 20, 20, 114, 114, 48), - new DmParams(44, 44, 22, 22, 144, 144, 56), - new DmParams(48, 48, 24, 24, 174, 174, 68), - new DmParams(52, 52, 26, 26, 204, 102, 42), - new DmParams(64, 64, 16, 16, 280, 140, 56), - new DmParams(72, 72, 18, 18, 368, 92, 36), - new DmParams(80, 80, 20, 20, 456, 114, 48), - new DmParams(88, 88, 22, 22, 576, 144, 56), - new DmParams(96, 96, 24, 24, 696, 174, 68), - new DmParams(104, 104, 26, 26, 816, 136, 56), - new DmParams(120, 120, 20, 20, 1050, 175, 68), - new DmParams(132, 132, 22, 22, 1304, 163, 62), - new DmParams(144, 144, 24, 24, 1558, 156, 62)}; - - private static final String x12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static final String DEFAULT_DATA_MATRIX_ENCODING = "iso-8859-1"; + + private static final byte LATCH_B256 = (byte) 231; + + private static final byte LATCH_EDIFACT = (byte) 240; + + private static final byte LATCH_X12 = (byte) 238; + + private static final byte LATCH_TEXT = (byte) 239; + + private static final byte LATCH_C40 = (byte) 230; + + private static final byte UNLATCH = (byte) 254; + + private static final byte EXTENDED_ASCII = (byte) 235; + + private static final byte PADDING = (byte) 129; + + private String encoding; + + private static final DmParams[] dmSizes = { + new DmParams(10, 10, 10, 10, 3, 3, 5), + new DmParams(12, 12, 12, 12, 5, 5, 7), + new DmParams(8, 18, 8, 18, 5, 5, 7), + new DmParams(14, 14, 14, 14, 8, 8, 10), + new DmParams(8, 32, 8, 16, 10, 10, 11), + new DmParams(16, 16, 16, 16, 12, 12, 12), + new DmParams(12, 26, 12, 26, 16, 16, 14), + new DmParams(18, 18, 18, 18, 18, 18, 14), + new DmParams(20, 20, 20, 20, 22, 22, 18), + new DmParams(12, 36, 12, 18, 22, 22, 18), + new DmParams(22, 22, 22, 22, 30, 30, 20), + new DmParams(16, 36, 16, 18, 32, 32, 24), + new DmParams(24, 24, 24, 24, 36, 36, 24), + new DmParams(26, 26, 26, 26, 44, 44, 28), + new DmParams(16, 48, 16, 24, 49, 49, 28), + new DmParams(32, 32, 16, 16, 62, 62, 36), + new DmParams(36, 36, 18, 18, 86, 86, 42), + new DmParams(40, 40, 20, 20, 114, 114, 48), + new DmParams(44, 44, 22, 22, 144, 144, 56), + new DmParams(48, 48, 24, 24, 174, 174, 68), + new DmParams(52, 52, 26, 26, 204, 102, 42), + new DmParams(64, 64, 16, 16, 280, 140, 56), + new DmParams(72, 72, 18, 18, 368, 92, 36), + new DmParams(80, 80, 20, 20, 456, 114, 48), + new DmParams(88, 88, 22, 22, 576, 144, 56), + new DmParams(96, 96, 24, 24, 696, 174, 68), + new DmParams(104, 104, 26, 26, 816, 136, 56), + new DmParams(120, 120, 20, 20, 1050, 175, 68), + new DmParams(132, 132, 22, 22, 1304, 163, 62), + new DmParams(144, 144, 24, 24, 1558, 156, 62)}; + + private static final String X12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private int extOut; private short[] place; private byte[] image; @@ -155,12 +182,28 @@ public class BarcodeDatamatrix { private int width; private int ws; private int options; + // value f[i][j] is the optimal amount of bytes required to encode substring(0, j) + private static int[][] f; + // switchMode[i][j] = k means that when encoding j-th symbol with mode = i + 1, + // we have to encode the previous symbol with mode = k in order to get optimal f[i][j] value + private static int[][] switchMode; + private boolean forceSquareSize = false; /** * Creates an instance of this class. */ - public BarcodeDatamatrix() { + public BarcodeDatamatrix() { encoding = DEFAULT_DATA_MATRIX_ENCODING; } + + public BarcodeDatamatrix(String code) throws UnsupportedEncodingException { + encoding = DEFAULT_DATA_MATRIX_ENCODING; + generate(code); + + } + + public BarcodeDatamatrix(String code, String encoding) throws UnsupportedEncodingException { + this.encoding = encoding; + generate(code); } private void setBit(int x, int y, int xByte) { @@ -214,7 +257,7 @@ private static void makePadding(byte[] data, int position, int count) { //already in ascii mode if (count <= 0) return; - data[position++] = (byte)129; + data[position++] = PADDING; while (--count > 0) { int t = 129 + (position + 1) * 149 % 253 + 1; if (t > 254) @@ -227,66 +270,99 @@ private static boolean isDigit(int c) { return c >= '0' && c <= '9'; } - private static int asciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + // when symbolIndex is non-negative, textLength should equal 1. All other encodations behave the same way. + private static int asciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int symbolIndex, int prevEnc, int origDataOffset) { int ptrIn, ptrOut, c; ptrIn = textOffset; ptrOut = dataOffset; textLength += textOffset; dataLength += dataOffset; while (ptrIn < textLength) { + c = text[ptrIn++] & 0xff; + if (isDigit(c) && symbolIndex > 0 && prevEnc == DM_ASCII && isDigit(text[ptrIn - 2] & 0xff) + && data[dataOffset - 1] > 48 && data[dataOffset - 1] < 59) { + data[ptrOut - 1] = (byte) (((text[ptrIn - 2] & 0xff) - '0') * 10 + c - '0' + 130); + return ptrOut - origDataOffset; + } if (ptrOut >= dataLength) return -1; - c = text[ptrIn++] & 0xff; - if (isDigit(c) && ptrIn < textLength && isDigit(text[ptrIn] & 0xff)) { + + if (isDigit(c) && symbolIndex < 0 && ptrIn < textLength && isDigit(text[ptrIn] & 0xff)) { data[ptrOut++] = (byte)((c - '0') * 10 + (text[ptrIn++] & 0xff) - '0' + 130); } else if (c > 127) { if (ptrOut + 1 >= dataLength) return -1; - data[ptrOut++] = (byte)235; + data[ptrOut++] = EXTENDED_ASCII; data[ptrOut++] = (byte)(c - 128 + 1); } else { data[ptrOut++] = (byte)(c + 1); } } - return ptrOut - dataOffset; + return ptrOut - origDataOffset; } - private static int b256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { - int k, j, prn, tv, c; + private static int b256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength,int symbolIndex, int prevEnc, int origDataOffset) { + int minRequiredDataIncrement; if (textLength == 0) return 0; - if (textLength < 250 && textLength + 2 > dataLength) - return -1; - if (textLength >= 250 && textLength + 3 > dataLength) - return -1; - data[dataOffset] = (byte)231; + int simulatedDataOffset = dataOffset; + if (prevEnc != DM_B256) { + if (textLength < 250 && textLength + 2 > dataLength) + return -1; + if (textLength >= 250 && textLength + 3 > dataLength) + return -1; + data[dataOffset] = LATCH_B256; + } else { + int latestModeEntry = symbolIndex - 1; + while (latestModeEntry > 0 && switchMode[DM_B256 - 1][latestModeEntry] == DM_B256) { + latestModeEntry--; + } + textLength = symbolIndex - latestModeEntry + 1; + if (textLength != 250 && 1 > dataLength) + return -1; + if (textLength == 250 && 2 > dataLength) + return -1; + simulatedDataOffset -= (textLength - 1) + (textLength < 250 ? 2 : 3); + } if (textLength < 250) { - data[dataOffset + 1] = (byte)textLength; - k = 2; + data[simulatedDataOffset + 1] = (byte) textLength; + minRequiredDataIncrement = prevEnc != DM_B256 ? 2 : 0; + } else if (textLength == 250 && prevEnc == DM_B256) { + data[simulatedDataOffset + 1] = (byte) (textLength / 250 + 249); + for (int i = dataOffset + 1; i > simulatedDataOffset + 2; i--) + data[i] = data[i - 1]; + data[simulatedDataOffset + 2] = (byte) (textLength % 250); + minRequiredDataIncrement = 1; + } else { + data[simulatedDataOffset + 1] = (byte) (textLength / 250 + 249); + data[simulatedDataOffset + 2] = (byte) (textLength % 250); + minRequiredDataIncrement = prevEnc != DM_B256 ? 3 : 0; } - else { - data[dataOffset + 1] = (byte)(textLength / 250 + 249); - data[dataOffset + 2] = (byte)(textLength % 250); - k = 3; + if (prevEnc == DM_B256) + textLength = 1; + System.arraycopy(text, textOffset, data, minRequiredDataIncrement + dataOffset, textLength); + for (int j = prevEnc != DM_B256 ? dataOffset + 1 : dataOffset; j < minRequiredDataIncrement + textLength + dataOffset; ++j) { + randomizationAlgorithm255(data, j); } - System.arraycopy(text, textOffset, data, k + dataOffset, textLength); - k += textLength + dataOffset; - for (j = dataOffset + 1; j < k; ++j) { - c = data[j] & 0xff; - prn = 149 * (j + 1) % 255 + 1; - tv = c + prn; - if (tv > 255) - tv -= 256; - data[j] = (byte)tv; + if (prevEnc == DM_B256) + randomizationAlgorithm255(data, simulatedDataOffset + 1); + return textLength + dataOffset + minRequiredDataIncrement - origDataOffset; + } - } - return k - dataOffset; + private static void randomizationAlgorithm255(byte[] data, int j) { + int c = data[j] & 0xff; + int prn = 149 * (j + 1) % 255 + 1; + int tv = c + prn; + if (tv > 255) + tv -= 256; + data[j] = (byte) tv; } - private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { - int ptrIn, ptrOut, count, k, n, ci; + private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, int symbolIndex, int prevEnc, int origDataOffset) { + int ptrIn, ptrOut, count, k, n; + boolean latch = true; byte c; if (textLength == 0) return 0; @@ -295,12 +371,11 @@ private static int X12Encodation(byte[] text, int textOffset, int textLength, by byte[] x = new byte[textLength]; count = 0; for (; ptrIn < textLength; ++ptrIn) { - int i = x12.indexOf((char)text[ptrIn + textOffset]); + int i = X12.indexOf((char) text[ptrIn + textOffset]); if (i >= 0) { - x[ptrIn] = (byte)i; + x[ptrIn] = (byte) i; ++count; - } - else { + } else { x[ptrIn] = 100; if (count >= 6) count -= count / 3 * 3; @@ -317,42 +392,78 @@ private static int X12Encodation(byte[] text, int textOffset, int textLength, by c = 0; for (; ptrIn < textLength; ++ptrIn) { c = x[ptrIn]; - if (ptrOut >= dataLength) + if (ptrOut > dataLength) break; if (c < 40) { - if (ptrIn == 0 || ptrIn > 0 && x[ptrIn - 1] > 40) - data[dataOffset + ptrOut++] = (byte)238; + if (ptrIn == 0 && latch || ptrIn > 0 && x[ptrIn - 1] > 40) + data[dataOffset + ptrOut++] = LATCH_X12; if (ptrOut + 2 > dataLength) break; n = 1600 * x[ptrIn] + 40 * x[ptrIn + 1] + x[ptrIn + 2] + 1; - data[dataOffset + ptrOut++] = (byte)(n / 256); - data[dataOffset + ptrOut++] = (byte)n; + data[dataOffset + ptrOut++] = (byte) (n / 256); + data[dataOffset + ptrOut++] = (byte) n; ptrIn += 2; - } - else { - if (ptrIn > 0 && x[ptrIn - 1] < 40) - data[dataOffset + ptrOut++] = (byte)254; - ci = text[ptrIn + textOffset] & 0xff; - if (ci > 127) { - data[dataOffset + ptrOut++] = (byte)235; - ci -= 128; + } else { + boolean enterASCII = true; + if (symbolIndex <= 0) { + if (ptrIn > 0 && x[ptrIn - 1] < 40) + data[dataOffset + ptrOut++] = UNLATCH; + } else if (symbolIndex > 4 && prevEnc == DM_X12 && X12.indexOf((char) text[textOffset]) >= 0 && X12.indexOf((char) text[textOffset - 1]) >= 0) { + int latestModeEntry = symbolIndex - 1; + while (latestModeEntry > 0 && switchMode[DM_X12 - 1][latestModeEntry] == DM_X12 + && (X12.indexOf((char) text[textOffset - (symbolIndex - latestModeEntry + 1)])) >= 0) { + latestModeEntry--; + } + int unlatch = -1; + if (symbolIndex - latestModeEntry >= 5) { + for (int i = 1; i <= symbolIndex - latestModeEntry; i++) { + if (data[dataOffset - i] == UNLATCH) { + unlatch = dataOffset - i; + break; + } + } + int amountOfEncodedWithASCII = unlatch >= 0 ? dataOffset - unlatch - 1 : symbolIndex - latestModeEntry; + if (amountOfEncodedWithASCII % 3 == 2) { + enterASCII = false; + textLength = amountOfEncodedWithASCII + 1; + textOffset -= amountOfEncodedWithASCII; + dataLength += unlatch < 0 ? amountOfEncodedWithASCII : amountOfEncodedWithASCII + 1; + dataOffset -= unlatch < 0 ? amountOfEncodedWithASCII : amountOfEncodedWithASCII + 1; + ptrIn = -1; + latch = unlatch != dataOffset; + x = new byte[amountOfEncodedWithASCII + 1]; + for (int i = 0; i <= amountOfEncodedWithASCII; i++) { + x[i] = (byte) X12.indexOf((char) text[textOffset + i]); + } + } else { + x = new byte[1]; + x[0] = 100; + } + } + } + if (enterASCII) { + int i = asciiEncodation(text, textOffset + ptrIn, 1, data, dataOffset + ptrOut, dataLength, -1, -1, origDataOffset); + if (i < 0) + return -1; + if (data[dataOffset + ptrOut] == EXTENDED_ASCII) + ptrOut++; + ptrOut++; } - if (ptrOut >= dataLength) - break; - data[dataOffset + ptrOut++] = (byte)(ci + 1); } } c = 100; if (textLength > 0) c = x[textLength - 1]; - if (ptrIn != textLength || c < 40 && ptrOut >= dataLength) + if (ptrIn != textLength) return -1; if (c < 40) - data[dataOffset + ptrOut++] = (byte)254; - return ptrOut; + data[dataOffset + ptrOut++] = UNLATCH; + if (ptrOut > dataLength) + return -1; + return ptrOut + dataOffset - origDataOffset; } - private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength,int symbolIndex, int prevEnc, int origDataOffset, boolean sizeFixed) { int ptrIn, ptrOut, edi, pedi, c; if (textLength == 0) return 0; @@ -361,13 +472,138 @@ private static int EdifactEncodation(byte[] text, int textOffset, int textLength edi = 0; pedi = 18; boolean ascii = true; + int latestModeEntryActual = -1, latestModeEntryC40orX12 = -1, prevMode = -1; + if (prevEnc == DM_EDIFACT && ((text[textOffset] & 0xff & 0xe0) == 0x40 || (text[textOffset] & 0xff & 0xe0) == 0x20) && (text[textOffset] & 0xff) != '_' + && ((text[textOffset - 1] & 0xff & 0xe0) == 0x40 || (text[textOffset - 1] & 0xff & 0xe0) == 0x20) && (text[textOffset - 1] & 0xff) != '_') { + latestModeEntryActual = symbolIndex - 1; + while (latestModeEntryActual > 0 && switchMode[DM_EDIFACT - 1][latestModeEntryActual] == DM_EDIFACT) { + c = text[textOffset - (symbolIndex - latestModeEntryActual + 1)] & 0xff; + if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') { + latestModeEntryActual--; + } else + break; + } + prevMode = switchMode[DM_EDIFACT - 1][latestModeEntryActual] == DM_C40 + || switchMode[DM_EDIFACT - 1][latestModeEntryActual] == DM_X12 ? switchMode[DM_EDIFACT - 1][latestModeEntryActual] : -1; + if (prevMode > 0) + latestModeEntryC40orX12 = latestModeEntryActual; + while (prevMode > 0 && latestModeEntryC40orX12 > 0 && switchMode[prevMode - 1][latestModeEntryC40orX12] == prevMode) { + c = text[textOffset - (symbolIndex - latestModeEntryC40orX12 + 1)] & 0xff; + if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') { + latestModeEntryC40orX12--; + } else { + latestModeEntryC40orX12 = -1; + break; + } + } + } + int dataSize = dataOffset + dataLength; + boolean asciiOneSymbol = false; + if (symbolIndex != -1) + asciiOneSymbol = true; + int dataTaken = 0, dataRequired = 0; + if (latestModeEntryC40orX12 >= 0 && symbolIndex - latestModeEntryC40orX12 + 1 > 9) { + textLength = symbolIndex - latestModeEntryC40orX12 + 1; + dataTaken = 0; + dataRequired = 0; + dataRequired += 1 + (textLength / 4 * 3); + if (!sizeFixed && (symbolIndex == text.length - 1 || symbolIndex < 0) && textLength % 4 < 3) { + dataSize = Integer.MAX_VALUE; + for (int i = 0; i < dmSizes.length; ++i) { + if (dmSizes[i].dataSize >= dataRequired + textLength % 4) { + dataSize = dmSizes[i].dataSize; + break; + } + } + } + if (dataSize - dataOffset - dataRequired <= 2 && textLength % 4 <= 2) + dataRequired += (textLength % 4); + else { + dataRequired += (textLength % 4) + 1; + if (textLength % 4 == 3) + dataRequired--; + } + for (int i = dataOffset - 1; i >= 0; i--) { + dataTaken++; + if (data[i] == (prevMode == DM_C40 ? LATCH_C40 : LATCH_X12)) { + break; + } + } + if (dataRequired <= dataTaken) { + asciiOneSymbol = false; + textOffset -= textLength - 1; + dataOffset -= dataTaken; + dataLength += dataTaken; + } + } else if (latestModeEntryActual >= 0 && symbolIndex - latestModeEntryActual + 1 > 9) { + textLength = symbolIndex - latestModeEntryActual + 1; + dataRequired += 1 + (textLength / 4 * 3); + if (dataSize - dataOffset - dataRequired <= 2 && textLength % 4 <= 2) + dataRequired += (textLength % 4); + else { + dataRequired += (textLength % 4) + 1; + if (textLength % 4 == 3) + dataRequired--; + } + int dataNewOffset = 0; + int latchEdi = -1; + for (int i = origDataOffset; i < dataOffset; i++) + if (data[i] == LATCH_EDIFACT && dataOffset - i <= dataRequired) { + latchEdi = i; + break; + } + if (latchEdi != -1) { + dataTaken += dataOffset - latchEdi; + if ((text[textOffset] & 0xff) > 127) + dataTaken += 2; + else { + if (isDigit(text[textOffset] & 0xff) && isDigit(text[textOffset - 1] & 0xff) && + data[dataOffset - 1] >= 49 && data[dataOffset - 1] <= 58) { + dataTaken--; + } + dataTaken++; + } + dataNewOffset = dataOffset - latchEdi; + } else { + for (int j = symbolIndex - latestModeEntryActual; j >= 0; j--) { + if ((text[textOffset - j] & 0xff) > 127) + dataTaken += 2; + else { + if (j > 0 && isDigit(text[textOffset - j] & 0xff) && isDigit(text[textOffset - j + 1] & 0xff)) { + if (j == 1) + dataNewOffset = dataTaken; + j--; + } + dataTaken++; + } + if (j == 1) + dataNewOffset = dataTaken; + } + } + if (dataRequired <= dataTaken) { + asciiOneSymbol = false; + textOffset -= textLength - 1; + dataOffset -= dataNewOffset; + dataLength += dataNewOffset; + } + } + if (asciiOneSymbol) { + c = text[textOffset] & 0xff; + if (isDigit(c) && textOffset + ptrIn > 0 && isDigit(text[textOffset - 1] & 0xff) + && prevEnc == DM_EDIFACT && data[dataOffset - 1] >= 49 && data[dataOffset - 1] <= 58) { + data[dataOffset + ptrOut - 1] = (byte) (((text[textOffset - 1] & 0xff) - '0') * 10 + c - '0' + 130); + return dataOffset - origDataOffset; + } else { + return asciiEncodation(text, textOffset + ptrIn, 1, data, dataOffset + ptrOut, dataLength, -1, -1, origDataOffset); + } + } for (; ptrIn < textLength; ++ptrIn) { c = text[ptrIn + textOffset] & 0xff; if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') { if (ascii) { if (ptrOut + 1 > dataLength) break; - data[dataOffset + ptrOut++] = (byte)240; + data[dataOffset + ptrOut++] = LATCH_EDIFACT; ascii = false; } c &= 0x3f; @@ -375,96 +611,181 @@ private static int EdifactEncodation(byte[] text, int textOffset, int textLength if (pedi == 0) { if (ptrOut + 3 > dataLength) break; - data[dataOffset + ptrOut++] = (byte)(edi >> 16); - data[dataOffset + ptrOut++] = (byte)(edi >> 8); - data[dataOffset + ptrOut++] = (byte)edi; + data[dataOffset + ptrOut++] = (byte) (edi >> 16); + data[dataOffset + ptrOut++] = (byte) (edi >> 8); + data[dataOffset + ptrOut++] = (byte) edi; edi = 0; pedi = 18; - } - else + } else pedi -= 6; } else { if (!ascii) { edi |= ('_' & 0x3f) << pedi; if (ptrOut + 3 - pedi / 8 > dataLength) break; - data[dataOffset + ptrOut++] = (byte)(edi >> 16); + data[dataOffset + ptrOut++] = (byte) (edi >> 16); if (pedi <= 12) - data[dataOffset + ptrOut++] = (byte)(edi >> 8); + data[dataOffset + ptrOut++] = (byte) (edi >> 8); if (pedi <= 6) - data[dataOffset + ptrOut++] = (byte)edi; + data[dataOffset + ptrOut++] = (byte) edi; ascii = true; pedi = 18; edi = 0; } - if (c > 127) { - if (ptrOut >= dataLength) - break; - data[dataOffset + ptrOut++] = (byte)235; - c -= 128; + if (isDigit(c) && textOffset + ptrIn > 0 && isDigit(text[textOffset + ptrIn - 1] & 0xff) && + prevEnc == DM_EDIFACT && data[dataOffset - 1] >= 49 && data[dataOffset - 1] <= 58) { + data[dataOffset + ptrOut - 1] = (byte) (((text[textOffset - 1] & 0xff) - '0') * 10 + c - '0' + 130); + ptrOut--; + } else { + int i = asciiEncodation(text, textOffset + ptrIn, 1, data, dataOffset + ptrOut, dataLength, -1, -1, origDataOffset); + if (i < 0) + return -1; + if (data[dataOffset + ptrOut] == EXTENDED_ASCII) + ptrOut++; + ptrOut++; } - if (ptrOut >= dataLength) - break; - data[dataOffset + ptrOut++] = (byte)(c + 1); } } if (ptrIn != textLength) return -1; - int dataSize = Integer.MAX_VALUE; - for (int i = 0; i < dmSizes.length; ++i) { - if (dmSizes[i].dataSize >= dataOffset + ptrOut + (3-pedi/6)) { - dataSize = dmSizes[i].dataSize; - break; + if (!sizeFixed && (symbolIndex == text.length - 1 || symbolIndex < 0)) { + dataSize = Integer.MAX_VALUE; + for (int i = 0; i < dmSizes.length; ++i) { + if (dmSizes[i].dataSize >= dataOffset + ptrOut + (3 - pedi / 6)) { + dataSize = dmSizes[i].dataSize; + break; + } } } - if (dataSize - dataOffset - ptrOut <= 2 && pedi >= 6) { - //have to write up to 2 bytes and up to 2 symbols + if (pedi != 18 && ptrOut + 2 - pedi / 8 > dataLength) + return -1; if (pedi <= 12) { byte val = (byte) ((edi >> 18) & 0x3F); if ((val & 0x20) == 0) val |= 0x40; - data[dataOffset + ptrOut++] = (byte)(val + 1); + data[dataOffset + ptrOut++] = (byte) (val + 1); } if (pedi <= 6) { byte val = (byte) ((edi >> 12) & 0x3F); if ((val & 0x20) == 0) val |= 0x40; - data[dataOffset + ptrOut++] = (byte)(val + 1); + data[dataOffset + ptrOut++] = (byte) (val + 1); } } else if (!ascii) { edi |= ('_' & 0x3f) << pedi; if (ptrOut + 3 - pedi / 8 > dataLength) return -1; - data[dataOffset + ptrOut++] = (byte)(edi >> 16); + data[dataOffset + ptrOut++] = (byte) (edi >> 16); if (pedi <= 12) - data[dataOffset + ptrOut++] = (byte)(edi >> 8); + data[dataOffset + ptrOut++] = (byte) (edi >> 8); if (pedi <= 6) - data[dataOffset + ptrOut++] = (byte)edi; + data[dataOffset + ptrOut++] = (byte) edi; } - return ptrOut; + return ptrOut + dataOffset - origDataOffset; } - private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, boolean c40) { + + private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, boolean c40, int symbolIndex, int prevEnc, int origDataOffset) { int ptrIn, ptrOut, encPtr, last0, last1, i, a, c; String basic, shift2, shift3; if (textLength == 0) return 0; ptrIn = 0; ptrOut = 0; - if (c40) - data[dataOffset + ptrOut++] = (byte)230; - else - data[dataOffset + ptrOut++] = (byte)239; shift2 = "!\"#$%&'()*+,-./:;<=>?@[\\]^_"; if (c40) { basic = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; shift3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177"; - } - else { + } else { basic = " 0123456789abcdefghijklmnopqrstuvwxyz"; shift3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177"; } + boolean addLatch = true, usingASCII = false; + int mode = c40 ? DM_C40 : DM_TEXT; + if (prevEnc == mode) { + usingASCII = true; + int latestModeEntry = symbolIndex - 1; + while (latestModeEntry > 0 && switchMode[mode - 1][latestModeEntry] == mode) { + latestModeEntry--; + } + int unlatch = -1; + int dataAmountOfEncodedWithASCII = 0; + if (symbolIndex - latestModeEntry >= 5) { + for (i = symbolIndex - latestModeEntry; i > 0; i--) { + c = text[textOffset - i] & 0xff; + if (c > 127) { + dataAmountOfEncodedWithASCII += 2; + } else + dataAmountOfEncodedWithASCII++; + } + for (i = 1; i <= dataAmountOfEncodedWithASCII; i++) { + if (i > dataOffset) + break; + if (data[dataOffset - i] == UNLATCH) { + unlatch = dataOffset - i; + break; + } + } + int amountOfEncodedWithASCII = 0; + if (unlatch >= 0) + for (i = unlatch + 1; i < dataOffset; i++) { + if (data[i] == EXTENDED_ASCII) + i++; + if (data[i] >= -127 && data[i] <= -27) + amountOfEncodedWithASCII++; + amountOfEncodedWithASCII++; + } + else + amountOfEncodedWithASCII = symbolIndex - latestModeEntry; + int dataOffsetNew = 0; + for (i = amountOfEncodedWithASCII; i > 0; i--) { + int requiredCapacityForASCII = 0; + int requiredCapacityForC40orText = 0; + for (int j = i; j >= 0; j--) { + c = text[textOffset - j] & 0xff; + if (c > 127) { + c -= 128; + requiredCapacityForC40orText += 2; + } + requiredCapacityForC40orText += basic.indexOf((char) c) >= 0 ? 1 : 2; + if (c > 127) + requiredCapacityForASCII += 2; + else { + if (j > 0 && isDigit(c) && isDigit(text[textOffset - j + 1] & 0xff)) { + requiredCapacityForC40orText += basic.indexOf((char) text[textOffset - j + 1]) >= 0 ? 1 : 2; + j--; + dataOffsetNew = requiredCapacityForASCII + 1; + } + requiredCapacityForASCII++; + } + if (j == 1) + dataOffsetNew = requiredCapacityForASCII; + } + addLatch = unlatch < 0 ? true : (dataOffset - requiredCapacityForASCII != unlatch); + if (requiredCapacityForC40orText % 3 == 0 && + requiredCapacityForC40orText / 3 * 2 + (addLatch ? 2 : 0) < requiredCapacityForASCII) { + usingASCII = false; + textLength = i + 1; + textOffset -= i; + dataOffset -= addLatch ? dataOffsetNew : dataOffsetNew + 1; + dataLength += addLatch ? dataOffsetNew : dataOffsetNew + 1; + break; + } + if (isDigit(text[textOffset - i] & 0xff) && isDigit(text[textOffset - i + 1] & 0xff)) + i--; + } + } + } else if (symbolIndex != -1) + usingASCII = true; + if (usingASCII) + return asciiEncodation(text, textOffset, 1, data, dataOffset, dataLength, prevEnc == mode ? 1 : -1, DM_ASCII, origDataOffset); + if (addLatch) { + if (c40) + data[dataOffset + ptrOut++] = LATCH_C40; + else + data[dataOffset + ptrOut++] = LATCH_TEXT; + } int[] enc = new int[textLength * 4 + 10]; encPtr = 0; last0 = 0; @@ -480,19 +801,16 @@ private static int C40OrTextEncodation(byte[] text, int textOffset, int textLeng enc[encPtr++] = 1; enc[encPtr++] = 30; } - int idx = basic.indexOf((char)c); + int idx = basic.indexOf((char) c); if (idx >= 0) { enc[encPtr++] = idx + 3; - } - else if (c < 32) { + } else if (c < 32) { enc[encPtr++] = 0; enc[encPtr++] = c; - } - else if ((idx = shift2.indexOf((char)c)) >= 0) { + } else if ((idx = shift2.indexOf((char) c)) >= 0) { enc[encPtr++] = 1; enc[encPtr++] = idx; - } - else if ((idx = shift3.indexOf((char)c)) >= 0) { + } else if ((idx = shift3.indexOf((char) c)) >= 0) { enc[encPtr++] = 2; enc[encPtr++] = idx; } @@ -507,83 +825,126 @@ else if ((idx = shift3.indexOf((char)c)) >= 0) { i = 0; for (; i < encPtr; i += 3) { a = 1600 * enc[i] + 40 * enc[i + 1] + enc[i + 2] + 1; - data[dataOffset + ptrOut++] = (byte)(a / 256); - data[dataOffset + ptrOut++] = (byte)a; + data[dataOffset + ptrOut++] = (byte) (a / 256); + data[dataOffset + ptrOut++] = (byte) a; } - data[ptrOut++] = (byte)254; - i = asciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut); - if (i < 0) + if (dataLength - ptrOut > 2) + data[dataOffset + ptrOut++] = UNLATCH; + if (symbolIndex < 0 && textLength > ptrIn) { + i = asciiEncodation(text, textOffset + ptrIn, textLength - ptrIn, data, dataOffset + ptrOut, dataLength - ptrOut, -1, -1, origDataOffset); return i; - return ptrOut + i; + } + return ptrOut + dataOffset - origDataOffset; + } + + + private static int minValueInColumn(int[][] array, int column) { + int min = Integer.MAX_VALUE; + for (int i = 0; i < 6; i++) + if (array[i][column] < min && array[i][column] >= 0) + min = array[i][column]; + return min != Integer.MAX_VALUE ? min : -1; } - private static int getEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, int options, boolean firstMatch) { - int e, j, k; - int[] e1 = new int[6]; + private static int valuePositionInColumn(int[][] array, int column, int value) { + for (int i = 0; i < 6; i++) + if (array[i][column] == value) + return i; + return -1; + } + + private static void solveFAndSwitchMode(int[] forMin, int mode, int currIndex) { + if (forMin[mode] >= 0 && f[mode][currIndex - 1] >= 0) { + f[mode][currIndex] = forMin[mode]; + switchMode[mode][currIndex] = mode + 1; + } else { + f[mode][currIndex] = Integer.MAX_VALUE; + } + for (int i = 0; i < 6; i++) { + if (forMin[i] < f[mode][currIndex] && forMin[i] >= 0 && f[i][currIndex - 1] >= 0) { + f[mode][currIndex] = forMin[i]; + switchMode[mode][currIndex] = i + 1; + } + } + if (f[mode][currIndex] == Integer.MAX_VALUE) { + f[mode][currIndex] = -1; + } + } + + + private static int getEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, int options, boolean sizeFixed) { + int e; if (dataSize < 0) return -1; - e = -1; options &= 7; if (options == 0) { - e1[0] = asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); - if (firstMatch && e1[0] >= 0) - return e1[0]; - e1[1] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); - if (firstMatch && e1[1] >= 0) - return e1[1]; - e1[2] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); - if (firstMatch && e1[2] >= 0) - return e1[2]; - e1[3] = b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); - if (firstMatch && e1[3] >= 0) - return e1[3]; - e1[4] = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); - if (firstMatch && e1[4] >= 0) - return e1[4]; - e1[5] = EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); - if (firstMatch && e1[5] >= 0) - return e1[5]; - if (e1[0] < 0 && e1[1] < 0 && e1[2] < 0 && e1[3] < 0 && e1[4] < 0 && e1[5] < 0) { - return -1; + if (textSize == 0) + return 0; + byte[][] dataDynamic = new byte[6][data.length]; + for (int i = 0; i < 6; i++) { + System.arraycopy(data, 0, dataDynamic[i], 0, data.length); + switchMode[i][0] = i + 1; } - j = 0; - e = 99999; - for (k = 0; k < 6; ++k) { - if (e1[k] >= 0 && e1[k] < e) { - e = e1[k]; - j = k; + f[0][0] = asciiEncodation(text, textOffset, 1, dataDynamic[0], dataOffset, dataSize, 0, -1, dataOffset); + f[1][0] = C40OrTextEncodation(text, textOffset, 1, dataDynamic[1], dataOffset, dataSize, true, 0, -1, dataOffset); + f[2][0] = C40OrTextEncodation(text, textOffset, 1, dataDynamic[2], dataOffset, dataSize, false, 0, -1, dataOffset); + f[3][0] = b256Encodation(text, textOffset, 1, dataDynamic[3], dataOffset, dataSize, 0, -1, dataOffset); + f[4][0] = X12Encodation(text, textOffset, 1, dataDynamic[4], dataOffset, dataSize, 0, -1, dataOffset); + f[5][0] = EdifactEncodation(text, textOffset, 1, dataDynamic[5], dataOffset, dataSize, 0, -1, dataOffset, sizeFixed); + int[] dataNewOffset = new int[6]; + for (int i = 1; i < textSize; i++) { + int tempForMin[] = new int[6]; + for (int k = 0; k < 6; k++) { + dataNewOffset[k] = f[k][i - 1] >= 0 ? f[k][i - 1] : Integer.MAX_VALUE; + } + for (int currEnc = 0; currEnc < 6; currEnc++) { + byte[][] dataDynamicInner = new byte[6][data.length]; + for (int prevEnc = 0; prevEnc < 6; prevEnc++) { + System.arraycopy(dataDynamic[prevEnc], 0, dataDynamicInner[prevEnc], 0, data.length); + if (currEnc == 0) + tempForMin[prevEnc] = asciiEncodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], i, prevEnc + 1, dataOffset); + if (currEnc == 1) + tempForMin[prevEnc] = C40OrTextEncodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], true, i, prevEnc + 1, dataOffset); + if (currEnc == 2) + tempForMin[prevEnc] = C40OrTextEncodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], false, i, prevEnc + 1, dataOffset); + if (currEnc == 3) + tempForMin[prevEnc] = b256Encodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], i, prevEnc + 1, dataOffset); + if (currEnc == 4) + tempForMin[prevEnc] = X12Encodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], i, prevEnc + 1, dataOffset); + if (currEnc == 5) + tempForMin[prevEnc] = EdifactEncodation(text, textOffset + i, 1, dataDynamicInner[prevEnc], dataNewOffset[prevEnc] + dataOffset, dataSize - dataNewOffset[prevEnc], i, prevEnc + 1, dataOffset, sizeFixed); + + } + solveFAndSwitchMode(tempForMin, currEnc, i); + if (switchMode[currEnc][i] != 0) + System.arraycopy(dataDynamicInner[switchMode[currEnc][i] - 1], 0, dataDynamic[currEnc], 0, data.length); } } - if (j == 0) - e = asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); - else if (j == 1) - e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); - else if (j == 2) - e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); - else if (j == 3) - e = b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); - else if (j == 4) - e = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + e = minValueInColumn(f, textSize - 1); + if (e > dataSize || e < 0) + return -1; + int bestDataDynamicResultIndex = valuePositionInColumn(f, textSize - 1, e); + System.arraycopy(dataDynamic[bestDataDynamicResultIndex], 0, data, 0, data.length); return e; } switch (options) { - case DM_ASCII: - return asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); - case DM_C40: - return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); - case DM_TEXT: - return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); - case DM_B256: - return b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); - case DM_X21: - return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); - case DM_EDIFACT: - return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); - case DM_RAW: - if (textSize > dataSize) - return -1; - System.arraycopy(text, textOffset, data, dataOffset, textSize); - return textSize; + case DM_ASCII: + return asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset); + case DM_C40: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true, -1, -1, dataOffset); + case DM_TEXT: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false, -1, -1, dataOffset); + case DM_B256: + return b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset); + case DM_X12: + return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset); + case DM_EDIFACT: + return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize, -1, -1, dataOffset, sizeFixed); + case DM_RAW: + if (textSize > dataSize) + return -1; + System.arraycopy(text, textOffset, data, dataOffset, textSize); + return textSize; } return -1; } @@ -695,7 +1056,12 @@ else if (eci < 16383) { * @throws java.io.UnsupportedEncodingException on error */ public int generate(String text) throws UnsupportedEncodingException { - byte[] t = text.getBytes("iso-8859-1"); + byte[] t; + try { + t = text.getBytes(encoding); + }catch (UnsupportedEncodingException exc) { + throw new IllegalArgumentException("text has to be encoded in iso-8859-1"); + } return generate(t, 0, t.length); } @@ -712,6 +1078,7 @@ public int generate(String text) throws UnsupportedEncodingException { * DM_ERROR_EXTENSION - an error was while parsing an extension. */ public int generate(byte[] text, int textOffset, int textSize) { + int extCount, e, k, full; DmParams dm, last; byte[] data = new byte[2500]; @@ -721,6 +1088,8 @@ public int generate(byte[] text, int textOffset, int textSize) { return DM_ERROR_EXTENSION; } e = -1; + f = new int[6][textSize - extOut]; + switchMode = new int[6][textSize - extOut]; if (height == 0 || width == 0) { last = dmSizes[dmSizes.length - 1]; e = getEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, last.dataSize - extCount, options, false); @@ -729,14 +1098,13 @@ public int generate(byte[] text, int textOffset, int textSize) { } e += extCount; for (k = 0; k < dmSizes.length; ++k) { - if (dmSizes[k].dataSize >= e && (!forceSquareSize || dmSizes[k].width == dmSizes[k].height)) + if (dmSizes[k].dataSize >= e) break; } dm = dmSizes[k]; height = dm.height; width = dm.width; - } - else { + } else { for (k = 0; k < dmSizes.length; ++k) { if (height == dmSizes[k].height && width == dmSizes[k].width) break; diff --git a/itext/src/main/java/com/itextpdf/text/pdf/BaseFont.java b/itext/src/main/java/com/itextpdf/text/pdf/BaseFont.java index a65f263f08..a37659d49a 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/BaseFont.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/BaseFont.java @@ -1496,6 +1496,21 @@ public static ArrayList getDocumentFonts(PdfReader reader, int page) { return fonts; } + static PdfDictionary createBuiltInFontDictionary(String name) { + return createBuiltInFontDictionary(BuiltinFonts14.get(name)); + } + + private static PdfDictionary createBuiltInFontDictionary(PdfName name) { + if (name == null) { + return null; + } + PdfDictionary dictionary = new PdfDictionary(); + dictionary.put(PdfName.TYPE, PdfName.FONT); + dictionary.put(PdfName.BASEFONT, name); + dictionary.put(PdfName.SUBTYPE, PdfName.TYPE1); + return dictionary; + } + /** * Gets the smallest box enclosing the character contours. It will return * null if the font has not the information or the character has no diff --git a/itext/src/main/java/com/itextpdf/text/pdf/CFFFontSubset.java b/itext/src/main/java/com/itextpdf/text/pdf/CFFFontSubset.java index b7dde24a96..ca109bfa6a 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/CFFFontSubset.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/CFFFontSubset.java @@ -484,7 +484,7 @@ else if (fonts[Font].privateSubrs>=0) // Builds the New Local Subrs index NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID,RETURN_OP); //Builds the New Global Subrs index - NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed,RETURN_OP); + NewGSubrsIndex = BuildNewIndexAndCopyAllGSubrs(gsubrOffsets, RETURN_OP); } /** @@ -980,6 +980,54 @@ protected byte[] BuildNewIndex(int[] Offsets,HashMap Used,byte O return AssembleIndex(NewOffsets,NewObjects); } + /** + * Function builds the new offset array, object array and assembles the index. + * used for creating the glyph and subrs subsetted index + * + * @param Offsets the offset array of the original index + * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries + * @return the new index subset version + * @throws java.io.IOException + */ + protected byte[] BuildNewIndexAndCopyAllGSubrs(int[] Offsets, byte OperatorForUnusedEntries) throws java.io.IOException { + int unusedCount = 0; + int Offset = 0; + int[] NewOffsets = new int[Offsets.length]; + // Build the Offsets Array for the Subset + for (int i = 0; i < Offsets.length - 1; ++i) { + NewOffsets[i] = Offset; + Offset += Offsets[i + 1] - Offsets[i]; + } + // Else the same offset is kept in i+1. + NewOffsets[Offsets.length - 1] = Offset; + unusedCount++; + + // Offset var determines the size of the object array + byte[] NewObjects = new byte[Offset + unusedCount]; + // Build the new Object array + int unusedOffset = 0; + for (int i = 0; i < Offsets.length - 1; ++i) { + int start = NewOffsets[i]; + int end = NewOffsets[i + 1]; + NewOffsets[i] = start + unusedOffset; + // If start != End then the Object is used + // So, we will copy the object data from the font file + if (start != end) { + // All offsets are Global Offsets relative to the beginning of the font file. + // Jump the file pointer to the start address to read from. + buf.seek(Offsets[i]); + // Read from the buffer and write into the array at start. + buf.readFully(NewObjects, start + unusedOffset, end - start); + } else { + NewObjects[start + unusedOffset] = OperatorForUnusedEntries; + unusedOffset++; + } + } + NewOffsets[Offsets.length - 1] += unusedOffset; + // Use AssembleIndex to build the index from the offset & object arrays + return AssembleIndex(NewOffsets, NewObjects); + } + /** * Function creates the new index, inserting the count,offsetsize,offset array * and object array. @@ -995,9 +1043,9 @@ protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects) int Size = NewOffsets[NewOffsets.length-1]; // Calc the Offsize byte Offsize; - if (Size <= 0xff) Offsize = 1; - else if (Size <= 0xffff) Offsize = 2; - else if (Size <= 0xffffff) Offsize = 3; + if (Size < 0xff) Offsize = 1; + else if (Size < 0xffff) Offsize = 2; + else if (Size < 0xffffff) Offsize = 3; else Offsize = 4; // The byte array for the new index. The size is calc by // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array diff --git a/itext/src/main/java/com/itextpdf/text/pdf/FontSelector.java b/itext/src/main/java/com/itextpdf/text/pdf/FontSelector.java index a43163db3b..af07993914 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/FontSelector.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/FontSelector.java @@ -48,7 +48,10 @@ import com.itextpdf.text.Phrase; import com.itextpdf.text.Utilities; import com.itextpdf.text.error_messages.MessageLocalization; +import com.itextpdf.text.log.Logger; +import com.itextpdf.text.log.LoggerFactory; +import java.text.MessageFormat; import java.util.ArrayList; /** Selects the appropriate fonts that contain the glyphs needed to @@ -61,7 +64,10 @@ */ public class FontSelector { + private static final Logger LOGGER = LoggerFactory.getLogger(PdfSmartCopy.class); + protected ArrayList fonts = new ArrayList(); + protected ArrayList unsupportedFonts = new ArrayList(); protected Font currentFont = null; /** @@ -69,6 +75,10 @@ public class FontSelector { * @param font the Font */ public void addFont(Font font) { + if (!isSupported(font)) { + unsupportedFonts.add(font); + return; + } if (font.getBaseFont() != null) { fonts.add(font); return; @@ -85,7 +95,7 @@ public void addFont(Font font) { * @return a Phrase with one or more chunks */ public Phrase process(String text) { - if (fonts.size() == 0) + if (getSize() == 0) throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("no.font.is.defined")); char cc[] = text.toCharArray(); int len = cc.length; @@ -99,7 +109,7 @@ public Phrase process(String text) { } } if (sb.length() > 0) { - Chunk ck = new Chunk(sb.toString(), currentFont != null ? currentFont : fonts.get(0)); + Chunk ck = new Chunk(sb.toString(), currentFont != null ? currentFont : getFont(0)); ret.add(ck); } return ret; @@ -114,8 +124,8 @@ protected Chunk processChar(char[] cc, int k, StringBuffer sb) { Font font = null; if (Utilities.isSurrogatePair(cc, k)) { int u = Utilities.convertToUtf32(cc, k); - for (int f = 0; f < fonts.size(); ++f) { - font = fonts.get(f); + for (int f = 0; f < getSize(); ++f) { + font = getFont(f); if (font.getBaseFont().charExists(u) || Character.getType(u) == Character.FORMAT) { if (currentFont != font) { if (sb.length() > 0 && currentFont != null) { @@ -130,8 +140,8 @@ protected Chunk processChar(char[] cc, int k, StringBuffer sb) { } } } else { - for (int f = 0; f < fonts.size(); ++f) { - font = fonts.get(f); + for (int f = 0; f < getSize(); ++f) { + font = getFont(f); if (font.getBaseFont().charExists(c) || Character.getType(c) == Character.FORMAT) { if (currentFont != font) { if (sb.length() > 0 && currentFont != null) { @@ -148,4 +158,21 @@ protected Chunk processChar(char[] cc, int k, StringBuffer sb) { } return newChunk; } + + protected int getSize() { + return fonts.size() + unsupportedFonts.size(); + } + + protected Font getFont(int i) { + return i < fonts.size() ? fonts.get(i) : unsupportedFonts.get(i); + } + + private boolean isSupported(Font font) { + BaseFont bf = font.getBaseFont(); + if (bf instanceof TrueTypeFont && BaseFont.WINANSI.equals(bf.getEncoding()) && !((TrueTypeFont) bf).isWinAnsiSupported()) { + LOGGER.warn(MessageFormat.format("cmap(1, 0) not found for TrueType Font {0}, it is required for WinAnsi encoding.", font)); + return false; + } + return true; + } } diff --git a/itext/src/main/java/com/itextpdf/text/pdf/PdfDictionary.java b/itext/src/main/java/com/itextpdf/text/pdf/PdfDictionary.java index 438c07eec6..10e0d2cdb0 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/PdfDictionary.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/PdfDictionary.java @@ -43,6 +43,7 @@ */ package com.itextpdf.text.pdf; +import com.itextpdf.text.error_messages.MessageLocalization; import com.itextpdf.text.pdf.internal.PdfIsoKeys; import java.io.IOException; @@ -188,6 +189,8 @@ public String toString() { * key */ public void put(final PdfName key, final PdfObject object) { + if (key == null) + throw new IllegalArgumentException(MessageLocalization.getComposedMessage("key.is.null")); if (object == null || object.isNull()) hashMap.remove(key); else @@ -207,6 +210,8 @@ public void put(final PdfName key, final PdfObject object) { * key */ public void putEx(final PdfName key, final PdfObject value) { + if (key == null) + throw new IllegalArgumentException(MessageLocalization.getComposedMessage("key.is.null")); if (value == null) return; put(key, value); diff --git a/itext/src/main/java/com/itextpdf/text/pdf/PdfPRow.java b/itext/src/main/java/com/itextpdf/text/pdf/PdfPRow.java index ad67fe7f5f..abbeb09456 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/PdfPRow.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/PdfPRow.java @@ -46,6 +46,7 @@ import java.util.HashMap; import com.itextpdf.text.*; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.interfaces.IAccessibleElement; @@ -709,7 +710,9 @@ public void copyRowContent(PdfPTable table, int idx) { * an empty row would result */ public PdfPRow splitRow(PdfPTable table, int rowIndex, float new_height) { - LOGGER.info(String.format("Splitting row %s available height: %s", rowIndex, new_height)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Splitting row %s available height: %s", rowIndex, new_height)); + } // second part of the row PdfPCell newCells[] = new PdfPCell[cells.length]; float calHs[] = new float[cells.length]; diff --git a/itext/src/main/java/com/itextpdf/text/pdf/PdfPTable.java b/itext/src/main/java/com/itextpdf/text/pdf/PdfPTable.java index 5d04d1cdf4..6ff3c9d57f 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/PdfPTable.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/PdfPTable.java @@ -54,6 +54,7 @@ import com.itextpdf.text.Rectangle; import com.itextpdf.text.api.Spaceable; import com.itextpdf.text.error_messages.MessageLocalization; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.events.PdfPTableEventForwarder; @@ -806,7 +807,9 @@ public float writeSelectedRows(int colStart, int colEnd, int rowStart, int rowEn colEnd = Math.min(colEnd, totalCols); } - LOGGER.info(String.format("Writing row %s to %s; column %s to %s", rowStart, rowEnd, colStart, colEnd)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Writing row %s to %s; column %s to %s", rowStart, rowEnd, colStart, colEnd)); + } float yPosStart = yPos; @@ -2107,7 +2110,9 @@ public boolean cellEnds() { * @since iText 5.4.3 */ public FittingRows getFittingRows(float availableHeight, int startIdx) { - LOGGER.info(String.format("getFittingRows(%s, %s)", availableHeight, startIdx)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("getFittingRows(%s, %s)", availableHeight, startIdx)); + } if ( startIdx > 0 && startIdx < rows.size() ) { assert (getRow(startIdx).getCells()[0] != null); // top left cell of current page may not be null } @@ -2133,7 +2138,9 @@ public FittingRows getFittingRows(float availableHeight, int startIdx) { state.consumeRowspan(completedRowsHeight, rowHeight); } else { state.beginCell(cell, completedRowsHeight, rowHeight); - LOGGER.info(String.format("Height after beginCell: %s (cell: %s)", state.height, cell.getCachedMaxHeight())); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Height after beginCell: %s (cell: %s)", state.height, cell.getCachedMaxHeight())); + } } if (state.cellEnds() && state.height > maxCompletedRowsHeight) { maxCompletedRowsHeight = state.height; diff --git a/itext/src/main/java/com/itextpdf/text/pdf/PdfReader.java b/itext/src/main/java/com/itextpdf/text/pdf/PdfReader.java index b1110b94f7..1b31387e0e 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/PdfReader.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/PdfReader.java @@ -63,6 +63,9 @@ import com.itextpdf.text.pdf.interfaces.PdfViewerPreferences; import com.itextpdf.text.pdf.internal.PdfViewerPreferencesImp; import com.itextpdf.text.pdf.security.ExternalDecryptionProcess; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cms.CMSEnvelopedData; +import org.bouncycastle.cms.RecipientInformation; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -86,10 +89,6 @@ import java.util.Stack; import java.util.zip.InflaterInputStream; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cms.CMSEnvelopedData; -import org.bouncycastle.cms.RecipientInformation; - /** * Reads a PDF document. * @author Paulo Soares @@ -1084,6 +1083,7 @@ else if (PdfName.AESV3.equals(dic.get(PdfName.CFM))) { } } else if (filter.equals(PdfName.PUBSEC)) { + decrypt.documentID = documentID; if ((cryptoMode & PdfWriter.ENCRYPTION_MASK) == PdfWriter.ENCRYPTION_AES_256) decrypt.setKey(encryptionKey); else diff --git a/itext/src/main/java/com/itextpdf/text/pdf/PdfStamperImp.java b/itext/src/main/java/com/itextpdf/text/pdf/PdfStamperImp.java index 37a6223fdf..c4ecf0a9c6 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/PdfStamperImp.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/PdfStamperImp.java @@ -52,8 +52,12 @@ import com.itextpdf.text.Version; import com.itextpdf.text.error_messages.MessageLocalization; import com.itextpdf.text.exceptions.BadPasswordException; +import com.itextpdf.text.io.RandomAccessSource; +import com.itextpdf.text.io.RandomAccessSourceFactory; import com.itextpdf.text.log.Counter; import com.itextpdf.text.log.CounterFactory; +import com.itextpdf.text.log.Logger; +import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.AcroFields.Item; import com.itextpdf.text.pdf.collection.PdfCollection; import com.itextpdf.text.pdf.interfaces.PdfViewerPreferences; @@ -112,6 +116,7 @@ class PdfStamperImp extends PdfWriter { protected HashMap namedDestinations = new HashMap(); protected Counter COUNTER = CounterFactory.getCounter(PdfStamper.class); + private Logger logger; protected Counter getCounter() { return COUNTER; @@ -122,6 +127,27 @@ protected Counter getCounter() { * then original layers are never read - they are simply copied to the new document with whole original catalog. */ private boolean originalLayersAreRead = false; + //Hash map of standard fonts used in flattening of annotations to prevent fonts duplication + private HashMap builtInAnnotationFonts = new HashMap(); + private static HashMap fromShortToFullAnnotationFontNames = new HashMap(); + + static { + fromShortToFullAnnotationFontNames.put("CoBO", BaseFont.COURIER_BOLDOBLIQUE); + fromShortToFullAnnotationFontNames.put("CoBo", BaseFont.COURIER_BOLD); + fromShortToFullAnnotationFontNames.put("CoOb", BaseFont.COURIER_OBLIQUE); + fromShortToFullAnnotationFontNames.put("Cour", BaseFont.COURIER); + fromShortToFullAnnotationFontNames.put("HeBO", BaseFont.HELVETICA_BOLDOBLIQUE); + fromShortToFullAnnotationFontNames.put("HeBo", BaseFont.HELVETICA_BOLD); + fromShortToFullAnnotationFontNames.put("HeOb", BaseFont.HELVETICA_OBLIQUE); + fromShortToFullAnnotationFontNames.put("Helv", BaseFont.HELVETICA); + fromShortToFullAnnotationFontNames.put("Symb", BaseFont.SYMBOL); + fromShortToFullAnnotationFontNames.put("TiBI", BaseFont.TIMES_BOLDITALIC); + fromShortToFullAnnotationFontNames.put("TiBo", BaseFont.TIMES_BOLD); + fromShortToFullAnnotationFontNames.put("TiIt", BaseFont.TIMES_ITALIC); + fromShortToFullAnnotationFontNames.put("TiRo", BaseFont.TIMES_ROMAN); + fromShortToFullAnnotationFontNames.put("ZaDb", BaseFont.ZAPFDINGBATS); + } + private double[] DEFAULT_MATRIX = {1, 0, 0, 1, 0, 0}; /** @@ -137,6 +163,7 @@ protected Counter getCounter() { */ protected PdfStamperImp(PdfReader reader, OutputStream os, char pdfVersion, boolean append) throws DocumentException, IOException { super(new PdfDocument(), os); + this.logger = LoggerFactory.getLogger(PdfStamperImp.class); if (!reader.isOpenedWithFullPermissions()) throw new BadPasswordException(MessageLocalization.getComposedMessage("pdfreader.not.opened.with.owner.password")); if (reader.isTampered()) @@ -931,10 +958,14 @@ protected void flatFields() { PdfDictionary appDic = merged.getAsDict(PdfName.AP); PdfObject as_n = null; if (appDic != null) { - as_n = appDic.getAsStream(PdfName.N); + as_n = appDic.getDirectObject(PdfName.N); + if (as_n == null) + as_n = appDic.getAsStream(PdfName.N); if (as_n == null) as_n = appDic.getAsDict(PdfName.N); } + //The rotation can be already applied if the appearance stream was written to document during setField method + boolean applyRotation = false; if (acroFields.isGenerateAppearances()) { if (appDic == null || as_n == null) { try { @@ -950,6 +981,7 @@ protected void flatFields() { PdfArray bbox = stream.getAsArray(PdfName.BBOX); PdfArray rect = merged.getAsArray(PdfName.RECT); if (bbox != null && rect != null) { + applyRotation = true; float rectWidth = rect.getAsNumber(2).floatValue() - rect.getAsNumber(0).floatValue(); float bboxWidth = bbox.getAsNumber(2).floatValue() - bbox.getAsNumber(0).floatValue(); float rectHeight = rect.getAsNumber(3).floatValue() - rect.getAsNumber(1).floatValue(); @@ -1034,23 +1066,27 @@ else if (objReal instanceof PdfStream) { Rectangle box = PdfReader.getNormalizedRectangle(merged.getAsArray(PdfName.RECT)); PdfContentByte cb = getOverContent(page); cb.setLiteral("Q "); - /* - Apply field rotation - */ - AffineTransform tf = new AffineTransform(); - double fieldRotation = 0; - if(merged.getAsDict(PdfName.MK) != null){ - if(merged.getAsDict(PdfName.MK).get(PdfName.R) != null){ - fieldRotation = merged.getAsDict(PdfName.MK).getAsNumber(PdfName.R).floatValue(); + if (applyRotation) { + /* + Apply field rotation + */ + AffineTransform tf = new AffineTransform(); + double fieldRotation = 0; + if (merged.getAsDict(PdfName.MK) != null) { + if (merged.getAsDict(PdfName.MK).get(PdfName.R) != null) { + fieldRotation = merged.getAsDict(PdfName.MK).getAsNumber(PdfName.R).floatValue(); + } } + //Cast to radians + fieldRotation = fieldRotation * Math.PI / 180; + //Clamp to [-2*Pi, 2*Pi] + fieldRotation = fieldRotation % (2 * Math.PI); + //Calculate transformation matrix + tf = calculateTemplateTransformationMatrix(tf, fieldRotation, box); + cb.addTemplate(app, tf); + } else { + cb.addTemplate(app, box.getLeft(), box.getBottom()); } - //Cast to radians - fieldRotation = fieldRotation * Math.PI/180; - //Clamp to [-2*Pi, 2*Pi] - fieldRotation = fieldRotation%(2*Math.PI); - //Calculate transformation matrix - tf = calculateTemplateTransformationMatrix(tf,fieldRotation,box); - cb.addTemplate(app, tf); cb.setLiteral("q "); } } @@ -1224,12 +1260,13 @@ private void flattenAnnotations(boolean flattenFreeTextAnnotations) { if (!(annoto instanceof PdfDictionary)) continue; PdfDictionary annDic = (PdfDictionary) annoto; + final PdfObject subType = annDic.get(PdfName.SUBTYPE); if (flattenFreeTextAnnotations) { - if (!(annDic.get(PdfName.SUBTYPE)).equals(PdfName.FREETEXT)) { + if (! PdfName.FREETEXT.equals(subType)) { continue; } } else { - if ((annDic.get(PdfName.SUBTYPE)).equals(PdfName.WIDGET)) { + if (PdfName.WIDGET.equals(subType)) { // skip widgets continue; } @@ -1255,26 +1292,95 @@ private void flattenAnnotations(boolean flattenFreeTextAnnotations) { ((PdfDictionary) objReal).put(PdfName.SUBTYPE, PdfName.FORM); app = new PdfAppearance((PdfIndirectReference) obj); } else { - if (objReal.isDictionary()) { - PdfName as_p = appDic.getAsName(PdfName.AS); - if (as_p != null) { - PdfIndirectReference iref = (PdfIndirectReference) ((PdfDictionary) objReal).get(as_p); - if (iref != null) { - app = new PdfAppearance(iref); - if (iref.isIndirect()) { - objReal = PdfReader.getPdfObject(iref); - ((PdfDictionary) objReal).put(PdfName.SUBTYPE, PdfName.FORM); + if (objReal != null ) { + if (objReal.isDictionary()) { + PdfName as_p = appDic.getAsName(PdfName.AS); + if (as_p != null) { + PdfIndirectReference iref = (PdfIndirectReference) ( (PdfDictionary) objReal ).get(as_p); + if (iref != null) { + app = new PdfAppearance(iref); + if (iref.isIndirect()) { + objReal = PdfReader.getPdfObject(iref); + ( (PdfDictionary) objReal ).put(PdfName.SUBTYPE, PdfName.FORM); + } + } + } + } + } else { + if ( PdfName.FREETEXT.equals(subType) ) { + final PdfString defaultAppearancePdfString = annDic.getAsString(PdfName.DA); + if (defaultAppearancePdfString != null) { + final PdfString freeTextContent = annDic.getAsString(PdfName.CONTENTS); + final String defaultAppearanceString = defaultAppearancePdfString.toString(); + + //It is not stated in spec, but acrobat seems to support standard font names in DA + //So we need to check if the font is built-in and specify it explicitly. + PdfIndirectReference fontReference = null; + PdfName pdfFontName = null; + try { + RandomAccessSource source = new RandomAccessSourceFactory().createSource(defaultAppearancePdfString.getBytes()); + PdfContentParser ps = new PdfContentParser(new PRTokeniser(new RandomAccessFileOrArray(source))); + ArrayList operands = new ArrayList(); + while (ps.parse(operands).size() > 0) { + PdfLiteral operator = (PdfLiteral)operands.get(operands.size()-1); + if (operator.toString().equals("Tf")) { + pdfFontName = (PdfName) operands.get(0); + String fontName = pdfFontName.toString().substring(1); + String fullName = fromShortToFullAnnotationFontNames.get(fontName); + if (fullName == null) { + fullName = fontName; + } + fontReference = builtInAnnotationFonts.get(fullName); + if (fontReference == null) { + PdfDictionary dic = BaseFont.createBuiltInFontDictionary(fullName); + if (dic != null) { + fontReference = addToBody(dic).getIndirectReference(); + builtInAnnotationFonts.put(fullName, fontReference); + } + } + } + } + } catch (Exception any) { + logger.warn(MessageLocalization.getComposedMessage("error.resolving.freetext.font")); + break; } + + app = new PdfAppearance(this); + // it is unclear from spec were referenced from DA font should be (since annotations doesn't have DR), so in case it not built-in + // quickly and naively flattening the freetext annotation + if (fontReference != null) { + app.getPageResources().addFont(pdfFontName, fontReference); + } + app.saveState(); + app.beginText(); + app.setLiteral(defaultAppearanceString); + app.setLiteral("(" + freeTextContent.toString() + ") Tj\n"); + app.endText(); + app.restoreState(); + } else { + // The DA entry is required for free text annotations + // Not throwing an exception as we don't want to stop the flow, result is that this annotation won't be flattened. + this.logger.warn(MessageLocalization.getComposedMessage("freetext.annotation.doesnt.contain.da")); } + } else { + this.logger.warn(MessageLocalization.getComposedMessage("annotation.type.not.supported.flattening")); } } } if (app != null) { Rectangle rect = PdfReader.getNormalizedRectangle(annDic.getAsArray(PdfName.RECT)); - Rectangle bBox = PdfReader.getNormalizedRectangle((objDict.getAsArray(PdfName.BBOX))); + Rectangle bBox = null; + + if ( objDict != null ) { + bBox = PdfReader.getNormalizedRectangle((objDict.getAsArray(PdfName.BBOX))); + } else { + bBox = new Rectangle(0,0, rect.getWidth(), rect.getHeight()); + app.setBoundingBox(bBox); + } + PdfContentByte cb = getOverContent(page); cb.setLiteral("Q "); - if (objDict.getAsArray(PdfName.MATRIX) != null && + if (objDict != null && objDict.getAsArray(PdfName.MATRIX) != null && !Arrays.equals(DEFAULT_MATRIX, objDict.getAsArray(PdfName.MATRIX).asDoubleArray())) { double[] matrix = objDict.getAsArray(PdfName.MATRIX).asDoubleArray(); Rectangle transformBBox = transformBBoxByMatrix(bBox, matrix); diff --git a/itext/src/main/java/com/itextpdf/text/pdf/TrueTypeFont.java b/itext/src/main/java/com/itextpdf/text/pdf/TrueTypeFont.java index ddec387d68..4cd5961d94 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/TrueTypeFont.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/TrueTypeFont.java @@ -1808,5 +1808,12 @@ protected int[] getRawCharBBox(int c, String name) { return bboxes[metric[0]]; } - + /** + * Checks whether this font may be used with winansi encoding. + * + * @return true if the font can be correctly used with winansi encodings + */ + boolean isWinAnsiSupported() { + return cmap10 != null; + } } diff --git a/itext/src/main/java/com/itextpdf/text/pdf/XfaForm.java b/itext/src/main/java/com/itextpdf/text/pdf/XfaForm.java index d68f1cdb7d..61aa66d545 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/XfaForm.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/XfaForm.java @@ -52,6 +52,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.EmptyStackException; @@ -65,6 +66,7 @@ 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; @@ -141,6 +143,7 @@ else if (xfa instanceof PRStream) { DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance(); fact.setNamespaceAware(true); DocumentBuilder db = fact.newDocumentBuilder(); + db.setEntityResolver(new SafeEmptyEntityResolver()); domDocument = db.parse(new ByteArrayInputStream(bout.toByteArray())); extractNodes(); } @@ -1159,6 +1162,7 @@ public void fillXfaForm(InputSource is, boolean readOnly) throws IOException { DocumentBuilder db; try { db = dbf.newDocumentBuilder(); + db.setEntityResolver(new SafeEmptyEntityResolver()); Document newdoc = db.parse(is); fillXfaForm(newdoc.getDocumentElement(), readOnly); } catch (ParserConfigurationException e) { @@ -1223,5 +1227,10 @@ private Node getFirstElementNode(Node src) { return result; } + private static class SafeEmptyEntityResolver implements EntityResolver { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + } } diff --git a/itext/src/main/java/com/itextpdf/text/pdf/XfaXmlLocator.java b/itext/src/main/java/com/itextpdf/text/pdf/XfaXmlLocator.java index 860b8e5e36..84bb0a64a3 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/XfaXmlLocator.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/XfaXmlLocator.java @@ -48,6 +48,7 @@ import org.w3c.dom.Document; import org.xml.sax.SAXException; +import javax.xml.XMLConstants; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; @@ -101,6 +102,10 @@ public void setDocument(Document document) throws IOException, DocumentException ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); TransformerFactory tf = TransformerFactory.newInstance(); + try { + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (Exception exc) {} + Transformer trans = tf.newTransformer(); //Convert Document to byte[] to save to PDF diff --git a/itext/src/main/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparator.java b/itext/src/main/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparator.java index 5f88f9eee9..dbfca64018 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparator.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparator.java @@ -47,36 +47,27 @@ /** *

- * This works on CompositeCharcaters or Juktakshar-s of Indian languages like Bangla, Hindi, etc. CompositeCharcters + * This works on CompositeCharacters or Juktakshar-s of Indian languages like Bangla, Hindi, etc. CompositeCharacters * are single glyphs consisting of more than one characters. - *

+ *

*

* This class works on these CompositeCharacters and places the Strings having higher number - * of Characters before the one with lower no. This is necessay to properly display the CompositeCharacters + * of Characters before the one with lower no. This is necessary to properly display the CompositeCharacters * when they occur side by side. *

-// *

-// *

Examples of CompositeCharactes from Bangla

-// *
    -// *
  • �?�?�?
  • -// *
  • �?�?
  • -// *
  • �?�?ষ�?ম
  • -// *
  • �?�?ষ
  • -// *
-// *

* * @author Palash Ray */ public class IndicCompositeCharacterComparator implements Comparator { - + public int compare(String o1, String o2) { - if (o2.length() > o1.length()) { + if (o1.length() < o2.length()) { return 1; - } else if (o1.length() > o2.length()) { + } + if (o1.length() > o2.length()) { return -1; - } else { - return o1.compareTo(o2); } + return o1.compareTo(o2); } } diff --git a/itext/src/main/java/com/itextpdf/text/pdf/security/LtvVerifier.java b/itext/src/main/java/com/itextpdf/text/pdf/security/LtvVerifier.java index f595246b20..6f5f5e5dc6 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/security/LtvVerifier.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/security/LtvVerifier.java @@ -55,6 +55,7 @@ import java.util.Date; import java.util.List; +import com.itextpdf.text.log.Level; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.cert.ocsp.OCSPException; import org.bouncycastle.cert.ocsp.OCSPResp; @@ -109,7 +110,9 @@ public LtvVerifier(PdfReader reader) throws GeneralSecurityException { signatureName = names.get(names.size() - 1); this.signDate = new Date(); pkcs7 = coversWholeDocument(); - LOGGER.info(String.format("Checking %ssignature %s", pkcs7.isTsp() ? "document-level timestamp " : "", signatureName)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Checking %ssignature %s", pkcs7.isTsp() ? "document-level timestamp " : "", signatureName)); + } } /** @@ -292,7 +295,9 @@ public void switchToPreviousRevision() throws IOException, GeneralSecurityExcept names = fields.getSignatureNames(); signatureName = names.get(names.size() - 1); pkcs7 = coversWholeDocument(); - LOGGER.info(String.format("Checking %ssignature %s", pkcs7.isTsp() ? "document-level timestamp " : "", signatureName)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Checking %ssignature %s", pkcs7.isTsp() ? "document-level timestamp " : "", signatureName)); + } } else { LOGGER.info("No signatures in revision"); diff --git a/itext/src/main/java/com/itextpdf/text/pdf/security/OCSPVerifier.java b/itext/src/main/java/com/itextpdf/text/pdf/security/OCSPVerifier.java index 905c304958..20fc84cd41 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/security/OCSPVerifier.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/security/OCSPVerifier.java @@ -56,6 +56,7 @@ import java.util.Enumeration; import java.util.List; +import com.itextpdf.text.log.Level; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -170,10 +171,14 @@ public boolean verify(BasicOCSPResp ocspResp, X509Certificate signCert, X509Cert Date nextUpdate = resp[i].getNextUpdate(); if (nextUpdate == null) { nextUpdate = new Date(resp[i].getThisUpdate().getTime() + 180000l); - LOGGER.info(String.format("No 'next update' for OCSP Response; assuming %s", nextUpdate)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("No 'next update' for OCSP Response; assuming %s", nextUpdate)); + } } if (signDate.after(nextUpdate)) { - LOGGER.info(String.format("OCSP no longer valid: %s after %s", signDate, nextUpdate)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("OCSP no longer valid: %s after %s", signDate, nextUpdate)); + } continue; } // check the status of the certificate diff --git a/itext/src/main/java/com/itextpdf/text/pdf/security/TSAClientBouncyCastle.java b/itext/src/main/java/com/itextpdf/text/pdf/security/TSAClientBouncyCastle.java index 38c8d74589..7a086ce338 100644 --- a/itext/src/main/java/com/itextpdf/text/pdf/security/TSAClientBouncyCastle.java +++ b/itext/src/main/java/com/itextpdf/text/pdf/security/TSAClientBouncyCastle.java @@ -44,21 +44,10 @@ package com.itextpdf.text.pdf.security; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.net.URL; -import java.net.URLConnection; - import com.itextpdf.text.error_messages.MessageLocalization; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.codec.Base64; -import java.security.GeneralSecurityException; -import java.security.MessageDigest; - import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.cmp.PKIFailureInfo; import org.bouncycastle.tsp.TSPException; @@ -68,6 +57,16 @@ import org.bouncycastle.tsp.TimeStampToken; import org.bouncycastle.tsp.TimeStampTokenInfo; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.net.URL; +import java.net.URLConnection; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; + /** * Time Stamp Authority Client interface implementation using Bouncy Castle * org.bouncycastle.tsp package. @@ -105,7 +104,10 @@ public class TSAClientBouncyCastle implements TSAClient { /** Hash algorithm */ protected String digestAlgorithm; - + + /** TSA request policy */ + private String tsaReqPolicy = null; + /** * Creates an instance of a TSAClient that will use BouncyCastle. * @param url String - Time Stamp Authority URL (i.e. "http://tsatest1.digistamp.com/TSA") @@ -158,6 +160,14 @@ public int getTokenSizeEstimate() { return tokenSizeEstimate; } + public String getTSAReqPolicy() { + return tsaReqPolicy; + } + + public void setTSAReqPolicy(String tsaReqPolicy) { + this.tsaReqPolicy = tsaReqPolicy; + } + /** * Gets the MessageDigest to digest the data imprint * @return the digest algorithm name @@ -179,6 +189,9 @@ public byte[] getTimeStampToken(byte[] imprint) throws IOException, TSPException // Setup the time stamp request TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator(); tsqGenerator.setCertReq(true); + if (tsaReqPolicy != null && tsaReqPolicy.length() > 0) { + tsqGenerator.setReqPolicy(new ASN1ObjectIdentifier(tsaReqPolicy)); + } // tsqGenerator.setReqPolicy("1.3.6.1.4.1.601.10.3.1"); BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); TimeStampRequest request = tsqGenerator.generate(new ASN1ObjectIdentifier(DigestAlgorithms.getAllowedDigests(digestAlgorithm)), imprint, nonce); diff --git a/itext/src/main/java/com/itextpdf/text/xml/xmp/XmpReader.java b/itext/src/main/java/com/itextpdf/text/xml/xmp/XmpReader.java index ed789a7721..b04daa804e 100644 --- a/itext/src/main/java/com/itextpdf/text/xml/xmp/XmpReader.java +++ b/itext/src/main/java/com/itextpdf/text/xml/xmp/XmpReader.java @@ -46,6 +46,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -55,6 +56,8 @@ import org.w3c.dom.NamedNodeMap; 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; import com.itextpdf.text.ExceptionConverter; @@ -96,6 +99,7 @@ public XmpReader(byte[] bytes) throws SAXException, IOException { DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance(); fact.setNamespaceAware(true); DocumentBuilder db = fact.newDocumentBuilder(); + db.setEntityResolver(new SafeEmptyEntityResolver()); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); domDocument = db.parse(bais); } catch (ParserConfigurationException e) { @@ -219,4 +223,10 @@ public byte[] serializeDoc() throws IOException { fout.close(); return fout.toByteArray(); } + + private static class SafeEmptyEntityResolver implements EntityResolver { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + } } diff --git a/itext/src/main/resources/com/itextpdf/text/l10n/error/en.lng b/itext/src/main/resources/com/itextpdf/text/l10n/error/en.lng index 4686f1186c..032cef298e 100644 --- a/itext/src/main/resources/com/itextpdf/text/l10n/error/en.lng +++ b/itext/src/main/resources/com/itextpdf/text/l10n/error/en.lng @@ -74,6 +74,7 @@ an.uncolored.pattern.was.expected=An uncolored pattern was expected. an.uncolored.tile.pattern.can.not.have.another.pattern.or.shading.as.color=An uncolored tile pattern can not have another pattern or shading as color. annotation.of.type.1.should.have.contents.key=Annotation of type {1} should have Contents key. annotation.type.1.not.allowed=Annotation type {1} not allowed. +annotation.type.not.supported.flattening=This annotation is not supported for flattening. Skipping this annotation. appearance.dictionary.of.widget.subtype.and.btn.field.type.shall.contain.only.the.n.key.with.dictionary.value=Appearance dictionary of Widget subtype and Btn field type shall contain only the n key with dictionary value appearance.dictionary.shall.contain.only.the.n.key.with.stream.value=Appearance dictionary shall contain only the N key with stream value. append.mode.does.not.support.changing.the.encryption.status=Append mode does not support changing the encryption status. @@ -167,6 +168,7 @@ error.in.base64.code.reading.stream=Error in Base64 code reading stream. error.parsing.cmap.beginbfchar.expected.cosstring.or.cosname.and.not.1=Error parsing CMap beginbfchar, expected {COSString or COSName} and not {1} error.reading.objstm=Error reading ObjStm error.reading.string=Error reading string +error.resolving.freetext.font=Cannot resolve annotation's font. It won't be flattened error.with.jp.marker=Error with JP Marker every.annotation.shall.have.at.least.one.appearance.dictionary=Every annotation shall have at least one appearance dictionary exactly.one.colour.space.specification.shall.have.the.value.0x01.in.the.approx.field=Exactly one colour space specification shall have the value 0x01 in the APPROX field. @@ -194,6 +196,7 @@ font.1.with.2.is.not.recognized=Font '{1}' with '{2}' is not recognized. font.and.size.must.be.set.before.writing.any.text=Font and size must be set before writing any text font.size.too.small.1=Font size too small: {1} fontfactoryimp.cannot.be.null=FontFactoryImp cannot be null. +freetext.annotation.doesnt.contain.da=FreeText Annotation doesn't contain a DA. Not flattening this annotation. freetext.flattening.is.not.supported.in.append.mode=FreeText flattening is not supported in append mode. annotation.flattening.is.not.supported.in.append.mode=Annotation flattening is not supported in append mode. getcell.at.illegal.index.1.max.is.2=getCell at illegal index :{1} max is {2} @@ -272,6 +275,7 @@ it.is.not.possible.to.free.reader.in.merge.fields.mode=It is not possible to fre java.awt.image.fetch.aborted.or.errored=java.awt.Image fetch aborted or errored java.awt.image.interrupted.waiting.for.pixels=java.awt.Image Interrupted waiting for pixels! jpeg2000.enumerated.colour.space.19.(CIEJab).shall.not.be.used=JPEG2000 enumerated colour space 19 (CIEJab) shall not be used. +key.is.null=key is null. keyword.encrypt.shall.not.be.used.in.the.trailer.dictionary=Keyword Encrypt shall not be used in the trailer dictionary. lab.cs.black.point=The BlackPoint entry in Lab color space could be only an array of three numbers [XB YB ZB]. All three of these numbers shall be non-negative. Default value: [0.0 0.0 0.0]. lab.cs.range=The Range entry in Lab color space could be only an array of four numbers [amin amax bmin bmax]. Default value: [-100 100 -100 100]. @@ -392,6 +396,7 @@ stdcf.not.found.encryption=/StdCF not found (encryption) stream.could.not.be.compressed.filter.is.not.a.name.or.array=Stream could not be compressed: filter is not a name or array. stream.object.dictionary.shall.not.contain.the.f.ffilter.or.fdecodeparams.keys=Stream object dictionary shall not contain the F, FFilter or FDecodeParams keys. structparent.not.found=StructParent not found. +structparentid.not.found=StructParent ID not found. support.only.sha1.hash.algorithm=Support only SHA1 hash algorithm. support.only.rsa.and.dsa.algorithms=Support only RSA and DSA algorithms. invalid.structparent=Invalid StructParent. diff --git a/itext/src/main/resources/com/itextpdf/text/l10n/error/nl.lng b/itext/src/main/resources/com/itextpdf/text/l10n/error/nl.lng index 45d943870b..2e92042c40 100644 --- a/itext/src/main/resources/com/itextpdf/text/l10n/error/nl.lng +++ b/itext/src/main/resources/com/itextpdf/text/l10n/error/nl.lng @@ -74,6 +74,7 @@ an.uncolored.pattern.was.expected=Er werd een ongekleurd patroon verwacht. an.uncolored.tile.pattern.can.not.have.another.pattern.or.shading.as.color=Een ongekleurd tile pattern kan geen ander pattern of shading als color gebruiken. annotation.of.type.1.should.have.contents.key=Annotation van type {1} moet een Contents sleutel hebben. annotation.type.1.not.allowed=Annotation type {1} niet toegelaten. +annotation.type.not.supported.flattening=Dit annotatie type is niet ondersteund tijdens het flattenen. Deze wordt overgeslaan. appearance.dictionary.of.widget.subtype.and.btn.field.type.shall.contain.only.the.n.key.with.dictionary.value=Appearance dictionary van subtype Widget en field type Btn mag enkel de N sleutel met als waarde een Dictionaty bevatten appearance.dictionary.shall.contain.only.the.n.key.with.stream.value=Appearance dictionary mag enkel de N sleutel met een stream waarde bevatten. append.mode.does.not.support.changing.the.encryption.status=Append mode laat geen wijziging toe van de encryptie status. @@ -167,6 +168,7 @@ error.in.base64.code.reading.stream=Fout in de Base64 code reading stream. error.parsing.cmap.beginbfchar.expected.cosstring.or.cosname.and.not.1=Fout bij het parsen van CMap beginbfchar, {COSString or COSName} verwacht in plaats van {1} error.reading.objstm=Fout tijdens het lezen van ObjStm error.reading.string=Fout bij het lezen van een string +error.resolving.freetext.font=Kan het lettertype van annotatie niet oplossen. Het wordt niet afgedrukt error.with.jp.marker=Foute JP Marker every.annotation.shall.have.at.least.one.appearance.dictionary=Elke annotation moet ten minste 1 appearance dictionary hebben exactly.one.colour.space.specification.shall.have.the.value.0x01.in.the.approx.field=Exact 1 colour space specificatie moet de waarde 0x01 in het APPROX veld hebben. @@ -194,6 +196,7 @@ font.1.with.2.is.not.recognized=Font '{1}' met '{2}' werd niet herkend. font.and.size.must.be.set.before.writing.any.text=Font en size moeten bepaald zijn vooraleer je tekst schrijft. font.size.too.small.1=Font size te klein: {1} fontfactoryimp.cannot.be.null=FontFactoryImp kan niet null zijn. +freetext.annotation.doesnt.contain.da=FreeText Annotatie bevat geen DA. Deze annotatie kan niet worden geflattened en wordt overgeslaan. freetext.flattening.is.not.supported.in.append.mode=FreeText flattening is niet ondersteund in append mode. annotation.flattening.is.not.supported.in.append.mode=Het flattenen van annotations is niet ondersteund in append mode. getcell.at.illegal.index.1.max.is.2=getCell op ongeldige index:{1} maximum: {2} @@ -272,6 +275,7 @@ it.is.not.possible.to.free.reader.in.merge.fields.mode=freeReader is niet mogeli java.awt.image.fetch.aborted.or.errored=Ophalen van java.awt.Image afgebroken of misgelopen. java.awt.image.interrupted.waiting.for.pixels=java.awt.Image onderbroken; aan het wachten op pixels! jpeg2000.enumerated.colour.space.19.(CIEJab).shall.not.be.used=JPEG2000 enumerated colour space 19 (CIEJab) mag niet gebruikt worden. +key.is.null=sleutel is nul. keyword.encrypt.shall.not.be.used.in.the.trailer.dictionary=Keyword Encrypt mag niet gebruikt worden in de trailer dictionary. lab.cs.black.point=De BlackPoint entry in Lab color space mag enkel een array zijn van drie getallen [XB YB ZB]. Al deze getallen moeten niet-negatief zijn. Standaardwaarde: [0.0 0.0 0.0]. lab.cs.range=De Range entry in Lab color space mag enkel een array zijn van vier getallen [amin amax bmin bmax]. Standaardwaarde: [-100 100 -100 100]. @@ -392,6 +396,7 @@ stdcf.not.found.encryption=/StdCF niet gevonden (encryption) stream.could.not.be.compressed.filter.is.not.a.name.or.array=Stream kon niet gecomprimeerd worden: de filter is geen naam of array. stream.object.dictionary.shall.not.contain.the.f.ffilter.or.fdecodeparams.keys=Stream object dictionary mag geen F, FFilter of FDecodeParams sleutels bevatten. structparent.not.found=StructParent niet gevonden. +structparentid.not.found=StructParent ID niet gevonden. support.only.sha1.hash.algorithm=Enkel ondersteuning voor SHA1 hash algoritme. support.only.rsa.and.dsa.algorithms=Enkel ondersteuning voor RSA en DSA algoritmes. invalid.structparent=Ongeldige StructParent. diff --git a/itext/src/test/java/com/itextpdf/text/pdf/BarcodeDatamatrixTest/BarcodeDatamatrixTest.java b/itext/src/test/java/com/itextpdf/text/pdf/BarcodeDatamatrixTest/BarcodeDatamatrixTest.java new file mode 100644 index 0000000000..cd4b16939d --- /dev/null +++ b/itext/src/test/java/com/itextpdf/text/pdf/BarcodeDatamatrixTest/BarcodeDatamatrixTest.java @@ -0,0 +1,345 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.text.pdf.BarcodeDatamatrixTest; + +import com.itextpdf.awt.geom.AffineTransform; +import com.itextpdf.testutils.CompareTool; +import com.itextpdf.testutils.ITextTest; +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.PageSize; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.pdf.BarcodeDatamatrix; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfWriter; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + + +public class BarcodeDatamatrixTest extends ITextTest { + public static final String sourceFolder = "./src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/"; + public static final String destinationFolder = "./target/com/itextpdf/test/BarcodeDatamatrix/"; + + @Before + public void setUp() { + new File(destinationFolder).mkdirs(); + } + + + protected void makePdf(String outPdf) throws Exception { + + } + + protected String getOutPdf() { + return null; + } + + @Test + public void barcode01Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix01.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 01")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode02Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix02.pdf"; + String code = "\u0434\u0438\u043C\u0430";// ???? + String encoding = "UTF-8"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 02")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(code, encoding); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode03Test() throws DocumentException, IOException, InterruptedException { + String filename = "barcodeDataMatrix03.pdf"; + String code = "AbcdFFghijklmnopqrstuWXSQ"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 03")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setWidth(36); + barcode.setHeight(12); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.BLACK,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode04Test() throws DocumentException, IOException, InterruptedException{ + String filename = "barcodeDataMatrix04.pdf"; + String code = "01AbcdefgAbcdefg123451231231234"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 04")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setWidth(36); + barcode.setHeight(12); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.BLACK,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + + } + + @Test + public void barcode05Test()throws DocumentException, IOException, InterruptedException { + String filename = "barcodeDataMatrix05.pdf"; + String code = "aaabbbcccdddAAABBBAAABBaaabbbcccdddaaa"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 05")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setWidth(40); + barcode.setHeight(40); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.BLACK,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + + + } + + @Test + public void barcode06Test()throws DocumentException, IOException, InterruptedException { + String filename = "barcodeDataMatrix06.pdf"; + String code = ">>>\r>>>THIS VERY TEXT>>\r>"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 06")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setWidth(36); + barcode.setHeight(12); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.BLACK,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode07Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix07.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 07")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_ASCII); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode08Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix08.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 08")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_C40); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode09Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix09.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 09")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_TEXT); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode10Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix10.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 10")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_B256); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + + @Test + public void barcode11Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix11.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 11")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_X12); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + @Test + public void barcode12Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix12.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 12")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_EDIFACT); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } + @Test + public void barcode13Test() throws IOException, DocumentException, InterruptedException { + String filename = "barcodeDataMatrix13.pdf"; + String code = "AAAAAAAAAA;BBBBAAAA3;00028;BBBAA05;AAAA;AAAAAA;1234567;AQWXSZ;JEAN;;;;7894561;AQWXSZ;GEO;;;;1;1;1;1;0;0;1;0;1;0;0;0;1;0;1;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1"; + + Document document = new Document(PageSize.A4); + PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(destinationFolder + filename)); + document.open(); + document.add(new Paragraph("Datamatrix test 13")); + PdfContentByte cb = writer.getDirectContent(); + cb.concatCTM(AffineTransform.getTranslateInstance(PageSize.A4.getWidth()/2-100,PageSize.A4.getHeight()/2-100)); + BarcodeDatamatrix barcode = new BarcodeDatamatrix(); + barcode.setOptions(BarcodeDatamatrix.DM_RAW); + barcode.generate(code); + barcode.placeBarcode(cb, BaseColor.GREEN,5,5); + document.close(); + + Assert.assertNull(new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename, destinationFolder, "diff_")); + } +} diff --git a/itext/src/test/java/com/itextpdf/text/pdf/FlatteningTest.java b/itext/src/test/java/com/itextpdf/text/pdf/FlatteningTest.java index 05ed7b0aa6..4b6dac9f14 100644 --- a/itext/src/test/java/com/itextpdf/text/pdf/FlatteningTest.java +++ b/itext/src/test/java/com/itextpdf/text/pdf/FlatteningTest.java @@ -50,6 +50,8 @@ import com.itextpdf.text.Phrase; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.events.FieldPositioningEvents; +import junit.framework.Assert; +import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -58,10 +60,9 @@ import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; - -import org.junit.Test; - -import junit.framework.Assert; +import java.io.OutputStream; +import java.util.Map; +import java.util.Set; /** * @author Michael Demey @@ -71,6 +72,38 @@ public class FlatteningTest { private static final String RESOURCES_FOLDER = "./src/test/resources/com/itextpdf/text/pdf/FlatteningTest/"; private static final String OUTPUT_FOLDER = "./target/com/itextpdf/test/pdf/FlatteningTest/"; + @Test + public void testFlatteningNewAppearances() throws InterruptedException, DocumentException, IOException { + new File(OUTPUT_FOLDER).mkdirs(); + + final String OUT = "tpl3_flattened.pdf"; + + PdfReader reader = new PdfReader(RESOURCES_FOLDER + "tpl3.pdf"); + AcroFields fields = reader.getAcroFields(); + if (fields != null && fields.getFields() != null && fields.getFields().size() > 0) { + OutputStream out = null; + out = new FileOutputStream(OUTPUT_FOLDER + OUT); + PdfStamper stamp = new PdfStamper(reader, out); + stamp.setFormFlattening(true); + AcroFields form = stamp.getAcroFields(); + + Set> map = form.getFields().entrySet(); + for (Map.Entry e : map) { + form.setField(e.getKey(), e.getKey()); + } + + stamp.close(); + out.close(); + } + reader.close(); + + CompareTool compareTool = new CompareTool(); + String errorMessage = compareTool.compare(OUTPUT_FOLDER + OUT, RESOURCES_FOLDER + "cmp_" + OUT, OUTPUT_FOLDER, "diff"); + if (errorMessage != null) { + Assert.fail(errorMessage); + } + } + @Test public void testFlattening() throws IOException, DocumentException, InterruptedException { final String INPUT_FOLDER = RESOURCES_FOLDER + "input/"; @@ -322,4 +355,27 @@ public void testAnnotationFlatteningWithSkewAndRotation() throws IOException, Do Assert.fail(errorMessage); } } + + @Test + public void testRotatedFilledField() throws IOException, DocumentException, InterruptedException { + new File(OUTPUT_FOLDER).mkdirs(); + + String file = "rotatedField.pdf"; + PdfReader pdfReader = new PdfReader(RESOURCES_FOLDER + file); + PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(OUTPUT_FOLDER + file)); + + AcroFields fields = pdfStamper.getAcroFields(); + fields.setField("Text1", "TEST"); + fields.setGenerateAppearances(true); + + pdfStamper.setFormFlattening(true); + pdfStamper.close(); + pdfReader.close(); + // compare + CompareTool compareTool = new CompareTool(); + String errorMessage = compareTool.compareByContent(OUTPUT_FOLDER + file, RESOURCES_FOLDER + "cmp_" + file, OUTPUT_FOLDER, "diff"); + if (errorMessage != null) { + Assert.fail(errorMessage); + } + } } diff --git a/itext/src/test/java/com/itextpdf/text/pdf/FreeTextFlatteningTest.java b/itext/src/test/java/com/itextpdf/text/pdf/FreeTextFlatteningTest.java new file mode 100644 index 0000000000..9596687bd5 --- /dev/null +++ b/itext/src/test/java/com/itextpdf/text/pdf/FreeTextFlatteningTest.java @@ -0,0 +1,198 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.text.pdf; + +import com.itextpdf.testutils.CompareTool; +import com.itextpdf.text.DocumentException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.itextpdf.text.pdf.parser.ContentByteUtils; +import com.itextpdf.text.pdf.parser.ImageRenderInfo; +import com.itextpdf.text.pdf.parser.PdfContentStreamProcessor; +import com.itextpdf.text.pdf.parser.RenderListener; +import com.itextpdf.text.pdf.parser.TextRenderInfo; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class FreeTextFlatteningTest { + + private final static String FOLDER = "./src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/"; + private final static String TARGET = "./target/com/itextpdf/test/pdf/FreeTextFlattening/"; + + @BeforeClass + public static void setUp() { + new File(TARGET).mkdirs(); + } + + @Test + public void flattenCorrectlyTest() throws IOException, DocumentException, InterruptedException { + String outputFile = TARGET + "freetext-flattened.pdf"; + + flattenFreeText(FOLDER + "freetext.pdf", outputFile); + checkAnnotationSize(outputFile, 0); + + String errorMessage = new CompareTool().compareByContent(outputFile, FOLDER + "flattened.pdf", TARGET, "diff"); + if ( errorMessage != null ) { + Assert.fail(errorMessage); + } + } + + @Test + public void checkPageContentTest() throws IOException, DocumentException, InterruptedException { + checkPageContent(FOLDER + "flattened.pdf"); + } + + @Test + public void flattenWithoutDA() throws IOException, DocumentException { + String outputFile = TARGET + "freetext-flattened-no-da.pdf"; + + flattenFreeText(FOLDER + "freetext-no-da.pdf", outputFile); + checkAnnotationSize(outputFile, 1); + } + + @Test + public void flattenAndCheckCourier() throws IOException, DocumentException, InterruptedException { + String inputFile = FOLDER + "freetext-courier.pdf"; + String outputFile = TARGET + "freetext-courier-flattened.pdf"; + + flattenFreeText(inputFile, outputFile); + checkPageContent(outputFile); + } + + @Test + public void flattenAndCheckShortFontName() throws IOException, DocumentException, InterruptedException { + String inputFile = FOLDER + "freetext-times-short.pdf"; + String outputFile = TARGET + "freetext-times-short-flattened.pdf"; + + flattenFreeText(inputFile, outputFile); + checkPageContent(outputFile); + + String errorMessage = new CompareTool().compareByContent(outputFile, FOLDER + "cmp_freetext-times-short-flattened.pdf", TARGET, "diff_short"); + if ( errorMessage != null ) { + Assert.fail(errorMessage); + } + } + + private void checkAnnotationSize(String path, int expectedAnnotationsSize) throws IOException, DocumentException { + FileInputStream fin = null; + try { + fin = new FileInputStream(path); + checkAnnotationSize(fin, expectedAnnotationsSize); + } finally { + if (fin != null) { + fin.close(); + } + } + } + + private void checkAnnotationSize(InputStream inputStream, int expectedAnnotationsSize) throws IOException, DocumentException { + PdfReader reader = new PdfReader(inputStream); + PdfDictionary pageDictionary = reader.getPageN(1); + if ( pageDictionary.contains(PdfName.ANNOTS )) { + PdfArray annotations = pageDictionary.getAsArray(PdfName.ANNOTS); + Assert.assertTrue(annotations.size() == expectedAnnotationsSize); + } + } + + private void flattenFreeText(String inputPath, String outputPath) throws IOException, DocumentException { + FileInputStream fin = null; + FileOutputStream fout = null; + try { + fin = new FileInputStream(inputPath); + fout = new FileOutputStream(outputPath); + flattenFreeText(fin, fout); + } finally { + if (fin != null) { + fin.close(); + } + if (fout != null) { + fout.close(); + } + } + } + + private void flattenFreeText(final InputStream inputStream, OutputStream outputStream) throws IOException, DocumentException { + PdfReader reader = new PdfReader(inputStream); + PdfStamper stamper = new PdfStamper(reader, outputStream); + + stamper.setFormFlattening(true); + stamper.setFreeTextFlattening(true); + stamper.setAnnotationFlattening(true); + + stamper.close(); + } + + private void checkPageContent(String path) throws IOException, DocumentException { + PdfReader pdfReader = new PdfReader(path); + try { + PdfDictionary pageDic = pdfReader.getPageN(1); + + RenderListener dummy = new RenderListener() { + public void beginTextBlock() { + } + + public void renderText(TextRenderInfo renderInfo) { + } + + public void endTextBlock() { + } + + public void renderImage(ImageRenderInfo renderInfo) { + } + }; + PdfContentStreamProcessor processor = new PdfContentStreamProcessor(dummy); + + PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES); + processor.processContent(ContentByteUtils.getContentBytesForPage(pdfReader, 1), resourcesDic); + } finally { + pdfReader.close(); + } + } +} \ No newline at end of file diff --git a/itext/src/test/java/com/itextpdf/text/pdf/PdfCopyTest.java b/itext/src/test/java/com/itextpdf/text/pdf/PdfCopyTest.java index 5208f9fc51..aa3409d7a6 100644 --- a/itext/src/test/java/com/itextpdf/text/pdf/PdfCopyTest.java +++ b/itext/src/test/java/com/itextpdf/text/pdf/PdfCopyTest.java @@ -79,6 +79,7 @@ public class PdfCopyTest { @Before public void setUp() throws Exception { TestResourceUtils.purgeTempFiles(); + new File("./target/com/itextpdf/test/pdf/PdfCopyTest").mkdirs(); } @After diff --git a/itext/src/test/java/com/itextpdf/text/pdf/PdfDictionaryTest.java b/itext/src/test/java/com/itextpdf/text/pdf/PdfDictionaryTest.java new file mode 100644 index 0000000000..5c00ed4a98 --- /dev/null +++ b/itext/src/test/java/com/itextpdf/text/pdf/PdfDictionaryTest.java @@ -0,0 +1,97 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.text.pdf; + +import org.junit.Assert; +import org.junit.Test; + +public class PdfDictionaryTest { + @Test + public void pdfDictionaryGetReturnsNullIfKeyIsNull() { + PdfDictionary dictionary = new PdfDictionary(); + + PdfObject value = dictionary.get(null); + + Assert.assertNull(value); + } + + @Test + public void pdfDictionaryContainsReturnsFalseIfKeyIsNull() { + PdfDictionary dictionary = new PdfDictionary(); + + boolean contained = dictionary.contains(null); + + Assert.assertFalse(contained); + } + + @Test + public void pdfDictionaryRemoveDoesNothingIfKeyIsNull() { + PdfDictionary dictionary = new PdfDictionary(); + + dictionary.remove(null); + } + + @Test + public void pdfDictionaryPutThrowsExceptionIfKeyIsNull() { + PdfDictionary dictionary = new PdfDictionary(); + + try { + dictionary.put(null, new PdfName("null")); + Assert.fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + Assert.assertEquals(e.getMessage(), "key is null."); + } + } + + @Test + public void pdfDictionaryPutExThrowsExceptionIfKeyIsNull() { + PdfDictionary dictionary = new PdfDictionary(); + + try { + dictionary.putEx(null, new PdfName("null")); + Assert.fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + Assert.assertEquals(e.getMessage(), "key is null."); + } + } +} diff --git a/itext/src/test/java/com/itextpdf/text/pdf/PdfEncryptionTest.java b/itext/src/test/java/com/itextpdf/text/pdf/PdfEncryptionTest.java index 89f1c0c858..e520f3c67a 100644 --- a/itext/src/test/java/com/itextpdf/text/pdf/PdfEncryptionTest.java +++ b/itext/src/test/java/com/itextpdf/text/pdf/PdfEncryptionTest.java @@ -46,16 +46,35 @@ This file is part of the iText (R) project. import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Paragraph; +import com.itextpdf.text.pdf.security.BouncyCastleDigest; +import com.itextpdf.text.pdf.security.DigestAlgorithms; +import com.itextpdf.text.pdf.security.ExternalDigest; +import com.itextpdf.text.pdf.security.ExternalSignature; +import com.itextpdf.text.pdf.security.MakeSignature; +import com.itextpdf.text.pdf.security.PrivateKeySignature; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Before; +import org.junit.Test; + import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import org.junit.Before; -import org.junit.Test; - -import junit.framework.Assert; - -import static junit.framework.Assert.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import static junit.framework.Assert.assertNull; public class PdfEncryptionTest { @@ -119,4 +138,117 @@ public void computeUserPasswordAES256() throws Exception { assertNull(password); } + + @Test + public void encryptWithCertificateAndSignTest() throws IOException, DocumentException, GeneralSecurityException { + removeCryptographyRestrictions(); + Security.addProvider(new BouncyCastleProvider()); + String inPdf = SOURCE_FOLDER + "in.pdf"; + String outPdf = DEST_FOLDER + "encrypt_cert_signed.pdf"; + String tmpPdf = DEST_FOLDER + "encrypt_cert.pdf"; + + encryptPdfWithCertificate(inPdf, tmpPdf, SOURCE_FOLDER + "test.cer"); + + Certificate cert = getPublicCertificate(SOURCE_FOLDER + "test.cer"); + PrivateKey privateKey = getPrivateKey(SOURCE_FOLDER + "test.p12"); + certSign(getPublicCertificate(SOURCE_FOLDER + "test.cer"), privateKey, outPdf, new PdfReader(tmpPdf, cert, privateKey, new BouncyCastleProvider().getName()), "reason", "location"); + restoreCryptographyRestrictions(); + } + + private static void encryptPdfWithCertificate(String sourceDocument, String targetDocument, String certPath) throws IOException, DocumentException, CertificateException { + Certificate cert = getPublicCertificate(certPath); + Certificate[] certs = new Certificate[] {cert}; + PdfReader reader = new PdfReader(sourceDocument); + PdfStamper st = new PdfStamper(reader, new FileOutputStream(targetDocument), '\0', false); + int[] x = new int[1]; + x[0] = PdfWriter.ALLOW_SCREENREADERS; + st.setEncryption(certs, x, PdfWriter.STANDARD_ENCRYPTION_40); + st.close(); + } + + private static Certificate getPublicCertificate(String path) throws IOException, CertificateException { + FileInputStream is = new FileInputStream(path); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(is); + return cert; + } + + private static PrivateKey getPrivateKey(String path) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException { + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(new FileInputStream(path), "kspass".toCharArray()); + String alias = ks.aliases().nextElement(); + PrivateKey pk = (PrivateKey) ks.getKey(alias, "kspass".toCharArray()); + return pk; + } + + private static void certSign(Certificate cert, PrivateKey privateKey, String destinationPath, PdfReader reader, String reason, String location) throws IOException, DocumentException, GeneralSecurityException { + Certificate[] chain = new Certificate[] {cert}; + + BouncyCastleProvider provider = new BouncyCastleProvider(); + ExternalSignature pks = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA1, provider.getName()); + + FileOutputStream fout = new FileOutputStream(destinationPath); + PdfStamper stamper = PdfStamper.createSignature(reader, fout, '\0', null, true); + PdfSignatureAppearance appearance = stamper.getSignatureAppearance(); + appearance.setReason(reason); + appearance.setLocation(location); + ExternalDigest digest = new BouncyCastleDigest(); + MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, + MakeSignature.CryptoStandard.CADES); + stamper.close(); + } + + /** + * Due to import control restrictions by the governments of a few countries, + * the encryption libraries shipped by default with the Java SDK restrict the + * length, and as a result the strength, of encryption keys. Be aware that by + * using this method we remove cryptography restrictions via reflection for + * testing purposes. + *
+ * For more conventional way of solving this problem you need to replace the + * default security JARs in your Java installation with the Java Cryptography + * Extension (JCE) Unlimited Strength Jurisdiction Policy Files. These JARs + * are available for download from http://java.oracle.com/ in eligible countries. + */ + public static void removeCryptographyRestrictions() { + try { + Field field = Class.forName("javax.crypto.JceSecurity"). + getDeclaredField("isRestricted"); + if (field.isAccessible()) { + // unexpected case + return; + } + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + modifiersField.setAccessible(false); + + field.setAccessible(true); + if (field.getBoolean(null)) { + field.set(null, java.lang.Boolean.FALSE); + } else { + field.setAccessible(false); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * By using this method we restore cryptography restrictions via reflection. + */ + public static void restoreCryptographyRestrictions() { + try { + Field field = Class.forName("javax.crypto.JceSecurity"). + getDeclaredField("isRestricted"); + if (field.isAccessible()) { + field.set(null, java.lang.Boolean.TRUE); + field.setAccessible(false); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } diff --git a/itext/src/test/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparatorTest.java b/itext/src/test/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparatorTest.java new file mode 100644 index 0000000000..3077a668f7 --- /dev/null +++ b/itext/src/test/java/com/itextpdf/text/pdf/languages/IndicCompositeCharacterComparatorTest.java @@ -0,0 +1,83 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.text.pdf.languages; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class IndicCompositeCharacterComparatorTest { + + @Test + public void testLengthIsEqualAndStringsAreEqual() { + String oneString = "\u0938\u0924"; + String twoString = "\u0938\u0924"; + int result = new IndicCompositeCharacterComparator().compare(oneString, twoString); + assertTrue("expected to be equal", result == 0); + } + + @Test + public void testLengthIsEqualAndStringsAreNotEqual() { + String oneString = "\u0938\u0924"; + String twoString = "\u0924\u0938"; + int result = new IndicCompositeCharacterComparator().compare(oneString, twoString); + assertTrue("expected not to be equal", result != 0); + } + + @Test + public void testFirstStringIsShorter() { + String oneString = "\u0938\u0924"; + String twoString = "\u0938\u0924\u0938\u0924"; + int result = new IndicCompositeCharacterComparator().compare(oneString, twoString); + assertTrue("expected to be greater than", result >= 1); + } + + @Test + public void testFirstStringIsLonger() { + String oneString = "\u0938\u0924\u0938\u0924"; + String twoString = "\u0938\u0924"; + int result = new IndicCompositeCharacterComparator().compare(oneString, twoString); + assertTrue("expected to be less than", result <= -1); + } + +} \ No newline at end of file diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix01.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix01.pdf new file mode 100644 index 0000000000..21e96f9f9b Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix01.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix02.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix02.pdf new file mode 100644 index 0000000000..760f56e6d6 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix02.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix03.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix03.pdf new file mode 100644 index 0000000000..8e5ad2c9a9 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix03.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix04.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix04.pdf new file mode 100644 index 0000000000..dea77eb0a2 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix04.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix05.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix05.pdf new file mode 100644 index 0000000000..8e6a842b99 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix05.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix06.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix06.pdf new file mode 100644 index 0000000000..a90273e68e Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix06.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix07.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix07.pdf new file mode 100644 index 0000000000..42806bb1cf Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix07.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix08.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix08.pdf new file mode 100644 index 0000000000..dace7b8a69 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix08.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix09.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix09.pdf new file mode 100644 index 0000000000..327d5f4485 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix09.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix10.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix10.pdf new file mode 100644 index 0000000000..4940fc0ed7 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix10.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix11.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix11.pdf new file mode 100644 index 0000000000..917f3d483b Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix11.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix12.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix12.pdf new file mode 100644 index 0000000000..5113a3910f Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix12.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix13.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix13.pdf new file mode 100644 index 0000000000..74a8c4e59d Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/BarcodeDatamatrix/cmp_barcodeDataMatrix13.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_rotatedField.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_rotatedField.pdf new file mode 100644 index 0000000000..2ca54188af Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_rotatedField.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_tpl3_flattened.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_tpl3_flattened.pdf new file mode 100644 index 0000000000..0b680e7d67 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/cmp_tpl3_flattened.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/rotatedField.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/rotatedField.pdf new file mode 100644 index 0000000000..6c9b469faf Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/rotatedField.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/tpl3.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/tpl3.pdf new file mode 100644 index 0000000000..18bfb24421 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FlatteningTest/tpl3.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/cmp_freetext-times-short-flattened.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/cmp_freetext-times-short-flattened.pdf new file mode 100644 index 0000000000..de5a4c423d Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/cmp_freetext-times-short-flattened.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/flattened.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/flattened.pdf new file mode 100644 index 0000000000..18db54b3be Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/flattened.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-courier.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-courier.pdf new file mode 100644 index 0000000000..b6e6ffd975 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-courier.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-no-da.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-no-da.pdf new file mode 100644 index 0000000000..1305a4bcc2 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-no-da.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-times-short.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-times-short.pdf new file mode 100644 index 0000000000..3c03454c1f Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext-times-short.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext.pdf new file mode 100644 index 0000000000..36faaf32fa Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/FreeTextFlatteningTest/freetext.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/in.pdf b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/in.pdf new file mode 100644 index 0000000000..2f59b49e6a Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/in.pdf differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.cer b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.cer new file mode 100644 index 0000000000..fbaad2b382 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.cer differ diff --git a/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.p12 b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.p12 new file mode 100644 index 0000000000..dc8d373503 Binary files /dev/null and b/itext/src/test/resources/com/itextpdf/text/pdf/PdfEncryptionTest/test.p12 differ diff --git a/pdfa/pom.xml b/pdfa/pom.xml index c4f96d0d32..ff94b47c02 100644 --- a/pdfa/pom.xml +++ b/pdfa/pom.xml @@ -10,7 +10,7 @@ itext-pdfa - 5.5.11 + 5.5.12 iText PDF/A iText ISO-19005 Module @@ -144,18 +144,6 @@ http://developers.itextpdf.com/reference/classes -
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-11854164-1', 'itextpdf.com'); - ga('send', 'pageview'); - - - ]]>
diff --git a/pdfa/src/main/java/com/itextpdf/text/zugferd/InvoiceDOM.java b/pdfa/src/main/java/com/itextpdf/text/zugferd/InvoiceDOM.java index e727bb0163..4e452e8121 100644 --- a/pdfa/src/main/java/com/itextpdf/text/zugferd/InvoiceDOM.java +++ b/pdfa/src/main/java/com/itextpdf/text/zugferd/InvoiceDOM.java @@ -64,8 +64,10 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; import java.util.Date; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -82,6 +84,8 @@ import org.w3c.dom.NamedNodeMap; 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; /** @@ -121,8 +125,9 @@ public InvoiceDOM(BasicProfile data) // loading the XML template DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setEntityResolver(new SafeEmptyEntityResolver()); InputStream is = StreamUtil.getResourceStream("com/itextpdf/text/zugferd/zugferd-template.xml"); - doc = docBuilder.parse(is); + doc = docBuilder.parse(is); // importing the data importData(doc, data); } @@ -1161,11 +1166,14 @@ protected void importLineItemBasic(Element parent, public byte[] toXML() throws TransformerException { removeEmptyNodes(doc); TransformerFactory transformerFactory = TransformerFactory.newInstance(); + try { + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (Exception exc) {} Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - DOMSource source = new DOMSource(doc); + DOMSource source = new DOMSource(doc); ByteArrayOutputStream out = new ByteArrayOutputStream(); Result result = new StreamResult(out); transformer.transform(source, result); @@ -1203,4 +1211,10 @@ protected void check(String s, String message) throws DataIncompleteException { if (s == null || s.trim().length() == 0) throw new DataIncompleteException(message); } + + private static class SafeEmptyEntityResolver implements EntityResolver { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + } } diff --git a/pdfa/src/test/resources/com/itextpdf/text/pdf/cidset/cmp_cidFontCheckTest3.pdf b/pdfa/src/test/resources/com/itextpdf/text/pdf/cidset/cmp_cidFontCheckTest3.pdf index 5a6ed82127..12a1e8aa6f 100644 Binary files a/pdfa/src/test/resources/com/itextpdf/text/pdf/cidset/cmp_cidFontCheckTest3.pdf and b/pdfa/src/test/resources/com/itextpdf/text/pdf/cidset/cmp_cidFontCheckTest3.pdf differ diff --git a/pom.xml b/pom.xml index b64acf756d..50a62d271e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ root - 5.5.11 + 5.5.12 pom iText @@ -52,18 +52,6 @@ com.itextpdf.tool.xml* -
-(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ -(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), -m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) -})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - -ga('create', 'UA-11854164-1', 'itextpdf.com'); -ga('send', 'pageview'); - - - ]]>
diff --git a/xmlworker/pom.xml b/xmlworker/pom.xml index 80945915ee..17f860e374 100644 --- a/xmlworker/pom.xml +++ b/xmlworker/pom.xml @@ -11,7 +11,7 @@ com.itextpdf.tool xmlworker - 5.5.11 + 5.5.12 iText XML Worker Parses XML to PDF, with CSS support, using iText @@ -212,18 +212,6 @@ http://developers.itextpdf.com/reference/classes -
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-11854164-1', 'itextpdf.com'); - ga('send', 'pageview'); - - - ]]>
diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Link.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Link.java index 4dadb809fa..da3534a507 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Link.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Link.java @@ -47,6 +47,7 @@ import java.util.List; import com.itextpdf.text.Element; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.tool.xml.NoCustomContextException; @@ -78,9 +79,13 @@ public List start(final WorkerContext ctx, final Tag tag) { try { getCSSResolver(ctx).addCssFile(href, false); } catch (CssResolverException e) { - LOG.error(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.LINK_404), href), e); + if (LOG.isLogging(Level.ERROR)) { + LOG.error(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.LINK_404), href), e); + } } catch (NoCustomContextException e) { - LOG.warn(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.CUSTOMCONTEXT_404_CONTINUE), CssResolverPipeline.class.getName())); + if (LOG.isLogging(Level.WARN)) { + LOG.warn(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.CUSTOMCONTEXT_404_CONTINUE), CssResolverPipeline.class.getName())); + } } } } diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Style.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Style.java index 4ddedadf64..fbaf0dcf37 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Style.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/html/head/Style.java @@ -88,7 +88,9 @@ public List content(final WorkerContext ctx, final Tag tag, final Strin LOG.trace(content); } } catch (NoCustomContextException e) { - LOG.warn(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.CUSTOMCONTEXT_404_CONTINUE), CssResolverPipeline.class.getName())); + if (LOG.isLogging(Level.WARN)) { + LOG.warn(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.CUSTOMCONTEXT_404_CONTINUE), CssResolverPipeline.class.getName())); + } } return new ArrayList(0); } diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/StateController.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/StateController.java index d554306460..14e50d8485 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/StateController.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/StateController.java @@ -272,4 +272,8 @@ public XMLParser starComment() { public XMLParser closeStarComment() { return setState(this.closeStarComment); } + + public State getPreviousState() { + return previousState; + } } diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParser.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParser.java index a845420a4f..1a06d99fd0 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParser.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParser.java @@ -41,6 +41,12 @@ */ package com.itextpdf.tool.xml.parser; +import com.itextpdf.text.xml.XMLUtil; +import com.itextpdf.text.xml.simpleparser.IanaEncodings; +import com.itextpdf.tool.xml.parser.io.EncodingUtil; +import com.itextpdf.tool.xml.parser.io.MonitorInputReader; +import com.itextpdf.tool.xml.parser.io.ParserMonitor; + import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -50,14 +56,9 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import com.itextpdf.text.xml.XMLUtil; -import com.itextpdf.text.xml.simpleparser.IanaEncodings; -import com.itextpdf.tool.xml.parser.io.EncodingUtil; -import com.itextpdf.tool.xml.parser.io.MonitorInputReader; -import com.itextpdf.tool.xml.parser.io.ParserMonitor; - /** * Reads an XML file. Attach a {@link XMLParserListener} for receiving events. * @@ -73,6 +74,7 @@ public class XMLParser { private String text = null; private TagState tagState; private Charset charset; + private boolean decodeSpecialChars = true; /** * Constructs a default XMLParser ready for HTML/XHTML processing. @@ -217,7 +219,7 @@ public void parse(final Reader reader) throws IOException { /** * The actual parse method * - * @param r + * @param reader * @throws IOException */ private void parseWithReader(final Reader reader) throws IOException { @@ -366,9 +368,14 @@ public XMLParserMemory memory() { */ public void startElement() { currentTagState(TagState.OPEN); + String tagName = this.memory.getCurrentTag(); + Map attributes = this.memory.getAttributes(); + if (tagName.startsWith("?")) { + memory().processingInstruction().setLength(0); + } callText(); for (XMLParserListener l : listeners) { - l.startElement(this.memory.getCurrentTag(), this.memory.getAttributes(), this.memory.getNameSpace()); + l.startElement(tagName, attributes, this.memory.getNameSpace()); } this.memory().flushNameSpace(); } @@ -463,6 +470,18 @@ public void setMonitor(final ParserMonitor monitor) { this.monitor = monitor; } + /** + * Determines whether special chars like > will be decoded + * @param decodeSpecialChars true to decode, false to not decode + */ + public void setDecodeSpecialChars(boolean decodeSpecialChars) { + this.decodeSpecialChars = decodeSpecialChars; + } + + public boolean isDecodeSpecialChars() { + return decodeSpecialChars; + } + /** * @return the current buffer as a String */ diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParserMemory.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParserMemory.java index d0667567c3..ff7a15b62a 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParserMemory.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/XMLParserMemory.java @@ -45,7 +45,6 @@ import com.itextpdf.tool.xml.parser.state.InsideTagHTMLState; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -62,6 +61,7 @@ public class XMLParserMemory { private final StringBuilder currentEntity = new StringBuilder(); private final StringBuilder comment = new StringBuilder(); private final StringBuilder baos = new StringBuilder(); + private final StringBuilder processingInstruction = new StringBuilder(); private final Map attr; private String wsTag = ""; private String currentNameSpace = ""; @@ -102,6 +102,7 @@ public void currentAttr(final String attr) { public boolean hasCurrentAttribute() { return null != this.currentAttr; } + /** * Sets the current attribute value and adds the attribute (if it's not * null) to the attribute map. @@ -161,6 +162,14 @@ public StringBuilder comment() { return this.comment; } + /** + * Returns the xml processing instruction buffer + * @return processing instruction buffer + */ + public StringBuilder processingInstruction() { + return this.processingInstruction; + } + /** * Returns last tag that needs to be taken into account for HTML Whitespace handling.
* Used by {@link InsideTagHTMLState}, only for HTML processing. diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/InsideTagHTMLState.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/InsideTagHTMLState.java index c1978f6652..3b96bae850 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/InsideTagHTMLState.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/InsideTagHTMLState.java @@ -100,7 +100,7 @@ public void process(final char character) { } else if (character == '&') { this.parser.selectState().specialChar(); } else { - if (character == '*' && this.parser.memory().lastChar() == '/') { + if (HTML.Tag.STYLE.equals(this.parser.currentTag()) && character == '*' && this.parser.memory().lastChar() == '/' && parser.memory().current().length() > 0) { this.parser.selectState().starComment(); this.parser.memory().current().deleteCharAt(this.parser.memory().current().lastIndexOf("/")); if (this.parser.bufferSize() > 0) { diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/ProcessingInstructionEncounteredState.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/ProcessingInstructionEncounteredState.java index 0c4629c7d7..35839c6307 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/ProcessingInstructionEncounteredState.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/ProcessingInstructionEncounteredState.java @@ -64,6 +64,7 @@ public ProcessingInstructionEncounteredState(final XMLParser parser) { */ public void process(final char character) { String tag = this.parser.bufferToString(); + this.parser.memory().processingInstruction().append(character); if (name == null && Character.isWhitespace(character)) { if (Character.isWhitespace(character)) { name = tag; diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SelfClosingTagState.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SelfClosingTagState.java index 2c80c34b48..ee357b0722 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SelfClosingTagState.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SelfClosingTagState.java @@ -72,6 +72,8 @@ public void process(final char character) { this.parser.flush(); this.parser.memory().flushNameSpace(); this.parser.selectState().inTag(); + } else if (this.parser.selectState().getPreviousState() instanceof ProcessingInstructionEncounteredState) { + this.parser.memory().processingInstruction().append(character); } } diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SpecialCharState.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SpecialCharState.java index 3b9a287117..8773d0d35c 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SpecialCharState.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/parser/state/SpecialCharState.java @@ -59,7 +59,7 @@ public class SpecialCharState implements State { * @param parser the XMLParser */ public SpecialCharState(final XMLParser parser) { - this.parser =parser; + this.parser = parser; } /* (non-Javadoc) @@ -71,7 +71,7 @@ public void process(final char character) { // if ("nbsp".equals(entity.toString())) { // parser.append(' '); // TODO check yes or no if it's good idea to transform   into a space ? // } else { - char decoded = EntitiesToUnicode.decodeEntity(entity.toString()); + char decoded = parser.isDecodeSpecialChars() ? EntitiesToUnicode.decodeEntity(entity.toString()) : 0; if (decoded == '\0') { parser.append('&').append(entity.toString()).append(';'); parser.memory().lastChar(';'); diff --git a/xmlworker/src/main/java/com/itextpdf/tool/xml/pipeline/end/PdfWriterPipeline.java b/xmlworker/src/main/java/com/itextpdf/tool/xml/pipeline/end/PdfWriterPipeline.java index 4ecb917069..8b993120d9 100644 --- a/xmlworker/src/main/java/com/itextpdf/tool/xml/pipeline/end/PdfWriterPipeline.java +++ b/xmlworker/src/main/java/com/itextpdf/tool/xml/pipeline/end/PdfWriterPipeline.java @@ -46,6 +46,7 @@ import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.PdfWriter; @@ -141,7 +142,7 @@ private void write(final WorkerContext context, final ProcessObject po) throws P if (writable instanceof WritableElement) { for (Element e : ((WritableElement) writable).elements()) { try { - if (!doc.add(e)) { + if (!doc.add(e) && LOG.isLogging(Level.TRACE)) { LOG.trace(String.format( LocaleMessages.getInstance().getMessage(LocaleMessages.ELEMENT_NOT_ADDED), e.toString())); diff --git a/xmlworker/src/test/java/com/itextpdf/tool/xml/BugRunnerTest.java b/xmlworker/src/test/java/com/itextpdf/tool/xml/BugRunnerTest.java index a6455c8686..39fb23d4d8 100644 --- a/xmlworker/src/test/java/com/itextpdf/tool/xml/BugRunnerTest.java +++ b/xmlworker/src/test/java/com/itextpdf/tool/xml/BugRunnerTest.java @@ -76,6 +76,7 @@ public void setup() { list.add("3353957.html"); list.add("ol-test.html"); list.add("processing-instructions.html"); + list.add("starcomments.html"); } @Test diff --git a/xmlworker/src/test/java/com/itextpdf/tool/xml/examples/custom/StarCommentTest02.java b/xmlworker/src/test/java/com/itextpdf/tool/xml/examples/custom/StarCommentTest02.java new file mode 100644 index 0000000000..335bacc9ce --- /dev/null +++ b/xmlworker/src/test/java/com/itextpdf/tool/xml/examples/custom/StarCommentTest02.java @@ -0,0 +1,51 @@ +/* + This file is part of the iText (R) project. + Copyright (c) 1998-2017 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.tool.xml.examples.custom; + +import com.itextpdf.tool.xml.examples.SampleTest; + +public class StarCommentTest02 extends SampleTest { + protected String getTestName() { + return "starComment02"; + } +} diff --git a/xmlworker/src/test/resources/bugs/starcomments.html b/xmlworker/src/test/resources/bugs/starcomments.html new file mode 100644 index 0000000000..4bd41b8d3e --- /dev/null +++ b/xmlworker/src/test/resources/bugs/starcomments.html @@ -0,0 +1,12 @@ + + + + + + http://www.example.com/
* hi + + + + / + + \ No newline at end of file diff --git a/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/background_image_div01.html b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/background_image_div01.html index 8c05c59e60..cd7488b2ac 100644 --- a/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/background_image_div01.html +++ b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/background_image_div01.html @@ -6,7 +6,7 @@ texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttextvtexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext -
+
image from web texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
diff --git a/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/itext.png b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/itext.png new file mode 100644 index 0000000000..d961f4efac Binary files /dev/null and b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/css/background/background_image/div/background_image_div01/itext.png differ diff --git a/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.html b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.html new file mode 100644 index 0000000000..3bc20ab075 --- /dev/null +++ b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.html @@ -0,0 +1,14 @@ + + + + + + +* hello world */ + +

Hello World!

+ +/* hello world */ + + + diff --git a/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.pdf b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.pdf new file mode 100644 index 0000000000..ef677e8cc6 Binary files /dev/null and b/xmlworker/src/test/resources/com/itextpdf/tool/xml/examples/custom/starComment02/starComment02.pdf differ diff --git a/xtra/pom.xml b/xtra/pom.xml index a6b715d74b..f6970d680c 100644 --- a/xtra/pom.xml +++ b/xtra/pom.xml @@ -10,7 +10,7 @@ itext-xtra - 5.5.11 + 5.5.12 iText Xtra iText Xtra, part of iText a Free Java-PDF library @@ -154,18 +154,6 @@ http://developers.itextpdf.com/reference/classes -
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-11854164-1', 'itextpdf.com'); - ga('send', 'pageview'); - - - ]]>
diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/mc/MCParser.java b/xtra/src/main/java/com/itextpdf/text/pdf/mc/MCParser.java index 0b06dce58c..ccdf043394 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/mc/MCParser.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/mc/MCParser.java @@ -54,6 +54,7 @@ import com.itextpdf.text.Rectangle; import com.itextpdf.text.error_messages.MessageLocalization; import com.itextpdf.text.io.RandomAccessSourceFactory; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.ByteBuffer; @@ -240,8 +241,10 @@ public void parse(PdfDictionary page, PdfIndirectReference pageref) throws IOExc baos.close(); stream.setData(baos.toByteArray()); // showing how many items are left - LOGGER.info(String.format("There are %d items left for processing", items.size())); - } + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("There are %d items left for processing", items.size())); + } + } /** * When an XObject with a StructParent is encountered, @@ -251,8 +254,10 @@ public void parse(PdfDictionary page, PdfIndirectReference pageref) throws IOExc protected void dealWithXObj(PdfName xobj) { PdfDictionary dict = xobjects.getAsStream(xobj); PdfNumber structParent = dict.getAsNumber(PdfName.STRUCTPARENT); - LOGGER.info(String.format("Encountered StructParent %s in content", structParent)); - if (structParent == null) + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Encountered StructParent %s in content", structParent)); + } + if (structParent == null) return; StructureItem item = items.get(0); if (item.checkStructParent(pageref.getNumber(), structParent.intValue()) == 1) @@ -271,8 +276,10 @@ protected void dealWithMcid(PdfNumber mcid) throws IOException, DocumentExceptio if (mcid == null) return; StructureItem item = items.get(0); - LOGGER.info(String.format("Encountered MCID %s in content, comparing with %s", mcid, item)); - switch (item.checkMCID(pageref.getNumber(), mcid.intValue())) { + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Encountered MCID %s in content, comparing with %s", mcid, item)); + } + switch (item.checkMCID(pageref.getNumber(), mcid.intValue())) { case 0 : StructureObject obj = (StructureObject)item; convertToXObject(obj); diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureItems.java b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureItems.java index 304e7cbed3..7d757eaf21 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureItems.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureItems.java @@ -50,6 +50,8 @@ import com.itextpdf.text.DocumentException; import com.itextpdf.text.error_messages.MessageLocalization; +import com.itextpdf.text.exceptions.InvalidPdfException; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.PdfArray; @@ -83,7 +85,7 @@ public class StructureItems extends ArrayList { * @param reader the reader holding the PDF to examine */ public StructureItems(PdfReader reader) - throws DocumentException { + throws DocumentException, InvalidPdfException { super(); PdfDictionary catalog = reader.getCatalog(); structTreeRoot = catalog.getAsDict(PdfName.STRUCTTREEROOT); @@ -117,8 +119,10 @@ public StructureItems(PdfReader reader) * @param ref the reference to the StructElem dictionary * @throws DocumentException */ - protected void processStructElems(PdfDictionary structElem, PdfIndirectReference ref) { - LOGGER.info(String.format("addStructureItems(%s, %s)", structElem, ref)); + protected void processStructElems(PdfDictionary structElem, PdfIndirectReference ref) throws InvalidPdfException { + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("addStructureItems(%s, %s)", structElem, ref)); + } if (structElem == null) return; processStructElemKids(structElem, ref, structElem.getDirectObject(PdfName.K)); @@ -132,8 +136,10 @@ protected void processStructElems(PdfDictionary structElem, PdfIndirectReference * @param ref the reference to the StructElem dictionary * @param object the kids object */ - protected void processStructElemKids(PdfDictionary structElem, PdfIndirectReference ref, PdfObject object) { - LOGGER.info(String.format("addStructureItem(%s, %s, %s)", structElem, ref, object)); + protected void processStructElemKids(PdfDictionary structElem, PdfIndirectReference ref, PdfObject object) throws InvalidPdfException { + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("addStructureItem(%s, %s, %s)", structElem, ref, object)); + } if (object == null) return; StructureItem item; diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureMCID.java b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureMCID.java index f04b731f5a..59def64c00 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureMCID.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureMCID.java @@ -63,7 +63,7 @@ public class StructureMCID extends StructureItem { * @param mcid an MCID */ public StructureMCID(PdfIndirectReference pg, PdfNumber mcid) { - this.pageref = pg.getNumber(); + this.pageref = pg == null ? -1 : pg.getNumber(); this.mcid = mcid.intValue(); } diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureObject.java b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureObject.java index 3138412265..2f6d8804b5 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureObject.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/mc/StructureObject.java @@ -43,10 +43,8 @@ */ package com.itextpdf.text.pdf.mc; -import com.itextpdf.text.pdf.PdfDictionary; -import com.itextpdf.text.pdf.PdfIndirectReference; -import com.itextpdf.text.pdf.PdfName; -import com.itextpdf.text.pdf.PdfObject; +import com.itextpdf.text.exceptions.InvalidPdfException; +import com.itextpdf.text.pdf.*; /** * A StructureItem that refers to an object from an OBJR dictionary. @@ -70,12 +68,15 @@ public class StructureObject extends StructureItem { * @param ref the reference of the parent structure element * @param dict the object reference dictionary */ - public StructureObject(PdfDictionary structElem, PdfIndirectReference ref, PdfDictionary dict) { + public StructureObject(PdfDictionary structElem, PdfIndirectReference ref, PdfDictionary dict) throws InvalidPdfException { this.structElem = structElem; this.ref = ref; this.obj = dict.getDirectObject(PdfName.OBJ); this.objref = dict.getAsIndirectObject(PdfName.OBJ); - this.structParent = ((PdfDictionary)obj).getAsNumber(PdfName.STRUCTPARENT).intValue(); + PdfNumber sp = ((PdfDictionary)obj).getAsNumber(PdfName.STRUCTPARENT); + if(sp == null) + throw new InvalidPdfException(""); + this.structParent = sp.intValue(); PdfIndirectReference pg = dict.getAsIndirectObject(PdfName.PG); if (pg == null) pg = structElem.getAsIndirectObject(PdfName.PG); diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpContentOperator.java b/xtra/src/main/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpContentOperator.java index 58549fcddc..5087cafaf6 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpContentOperator.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpContentOperator.java @@ -157,8 +157,6 @@ public void invoke(PdfContentStreamProcessor pdfContentStreamProcessor, PdfLiter disableOutput = true; } } - } else if (lineStyleOperators.contains(operatorStr)) { - disableOutput = true; } else if (textShowingOperators.contains(operatorStr) && !allChunksAreVisible(cleanUpStrategy.getChunks())) { disableOutput = true; diff --git a/xtra/src/main/java/com/itextpdf/text/pdf/util/SmartPdfSplitter.java b/xtra/src/main/java/com/itextpdf/text/pdf/util/SmartPdfSplitter.java index 1d05ce14a0..00e29f2f14 100644 --- a/xtra/src/main/java/com/itextpdf/text/pdf/util/SmartPdfSplitter.java +++ b/xtra/src/main/java/com/itextpdf/text/pdf/util/SmartPdfSplitter.java @@ -45,6 +45,7 @@ import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; +import com.itextpdf.text.log.Level; import com.itextpdf.text.log.Logger; import com.itextpdf.text.log.LoggerFactory; import com.itextpdf.text.pdf.PdfCopy; @@ -71,7 +72,9 @@ public SmartPdfSplitter(PdfReader reader) throws IOException { this.reader = reader; reader.setAppendable(true); numberOfPages = reader.getNumberOfPages(); - LOGGER.info(String.format("Creating a splitter for a document with %s pages", numberOfPages)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Creating a splitter for a document with %s pages", numberOfPages)); + } } public boolean hasMorePages() { @@ -102,13 +105,17 @@ public boolean split(OutputStream os, long sizeInBytes) throws IOException, Docu page = counter.getLength(resources); resources = counter.getResources(); length += page + trailer + xrefLength(resources.size()); - LOGGER.info(String.format("Page %s: Comparing %s with %s", currentPage, length, sizeInBytes)); - LOGGER.info(String.format(" page %s trailer %s xref %s", page, trailer, xrefLength(resources.size()))); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Page %s: Comparing %s with %s", currentPage, length, sizeInBytes)); + LOGGER.info(String.format(" page %s trailer %s xref %s", page, trailer, xrefLength(resources.size()))); + } if (!hasPage || length < sizeInBytes) { hasPage = true; copy.addPage(copy.getImportedPage(reader, currentPage)); length = copy.getOs().getCounter(); - LOGGER.info(String.format("Size after adding page: %s", length)); + if (LOGGER.isLogging(Level.INFO)) { + LOGGER.info(String.format("Size after adding page: %s", length)); + } if (length > sizeInBytes) overSized = true; currentPage++; } diff --git a/xtra/src/test/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpProcessorTest.java b/xtra/src/test/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpProcessorTest.java index dd75b35988..24a2368293 100644 --- a/xtra/src/test/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpProcessorTest.java +++ b/xtra/src/test/java/com/itextpdf/text/pdf/pdfcleanup/PdfCleanUpProcessorTest.java @@ -89,6 +89,7 @@ public static Collection data() { List cleanUpLocations2 = Arrays.asList(new PdfCleanUpLocation(1, new Rectangle(97f, 405f, 480f, 445f), BaseColor.GRAY)); List cleanUpLocations3 = Arrays.asList(new PdfCleanUpLocation(1, new Rectangle(97f, 605f, 480f, 645f), BaseColor.GRAY)); List cleanUpLocations4 = Arrays.asList(new PdfCleanUpLocation(1, new Rectangle(212, 394, 212 + 186, 394 + 170), null)); + List cleanUpLocations5= Arrays.asList(new PdfCleanUpLocation(1, new Rectangle(0f, 0f, 595f, 680f), BaseColor.GRAY)); return Arrays.asList(new Object[][] {{"page229.pdf", "page229_01.pdf", "cmp_page229_01.pdf", cleanUpLocations1}, {"page229-modified-Tc-Tw.pdf", "page229-modified-Tc-Tw.pdf", "cmp_page229-modified-Tc-Tw.pdf", cleanUpLocations1}, @@ -118,6 +119,8 @@ public static Collection data() { {"absentICentry.pdf", "absentICentry.pdf", "cmp_absentICentry.pdf", null}, {"lotOfDashes.pdf", "lotOfDashes.pdf", "cmp_lotOfDashes.pdf", null}, {"clipPathReduction.pdf", "clipPathReduction.pdf", "cmp_clipPathReduction.pdf", cleanUpLocations4}, + {"helloHelvetica.pdf", "helloHelvetica.pdf", "cmp_helloHelvetica.pdf", cleanUpLocations5}, + }); } diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedBezier.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedBezier.pdf index 6912938612..69785bcd95 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedBezier.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedBezier.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedClosedRotatedTriangles.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedClosedRotatedTriangles.pdf index d3de292d14..27a64fbae8 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedClosedRotatedTriangles.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedClosedRotatedTriangles.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedStyledClosedBezier.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedStyledClosedBezier.pdf index 53954703a8..cd850e07af 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedStyledClosedBezier.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_dashedStyledClosedBezier.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_degenerateCases.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_degenerateCases.pdf index f587b7c978..a76b247d0e 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_degenerateCases.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_degenerateCases.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_helloHelvetica.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_helloHelvetica.pdf new file mode 100644 index 0000000000..84fc609ba5 Binary files /dev/null and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_helloHelvetica.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_lotOfDashes.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_lotOfDashes.pdf index cc3719a15c..f7267c9067 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_lotOfDashes.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_lotOfDashes.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_miterTest.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_miterTest.pdf index 60047c0238..f027f975f8 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_miterTest.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_miterTest.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_styledLineArts.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_styledLineArts.pdf index d5c081b14f..e2b7952d7c 100644 Binary files a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_styledLineArts.pdf and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/cmp_styledLineArts.pdf differ diff --git a/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/helloHelvetica.pdf b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/helloHelvetica.pdf new file mode 100644 index 0000000000..d42e7c2588 Binary files /dev/null and b/xtra/src/test/resources/com/itextpdf/text/pdf/pdfcleanup/helloHelvetica.pdf differ