Skip to content

Commit 765865d

Browse files
Explicitly fallback to zero when NaN is attempted to be written
This was already how Java behaved in non-high-precision cases. However NaN processing would produce corrupted PDF in Java for highPrecision case and also caused exceptions in .NET. DEVSIX-2835
1 parent faedebb commit 765865d

File tree

5 files changed

+108
-6
lines changed

5 files changed

+108
-6
lines changed

io/src/main/java/com/itextpdf/io/LogMessageConstant.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public final class LogMessageConstant {
5252
public static final String ALREADY_FLUSHED_INDIRECT_OBJECT_MADE_FREE = "An attempt is made to free already flushed indirect object reference. Indirect reference wasn't freed.";
5353
public static final String ALREADY_TAGGED_HINT_MARKED_ARTIFACT = "A layout tagging hint for which an actual tag was already created in tags structure is marked as artifact. Existing tag will be left in the tags tree.";
5454
public static final String ASSOCIATED_FILE_SPEC_SHALL_INCLUDE_AFRELATIONSHIP = "For associated files their associated file specification dictionaries shall include the AFRelationship key.";
55+
public static final String ATTEMPT_PROCESS_NAN = "Attempt to process NaN in PdfNumber or when writing to PDF. Zero value will be used as a fallback.";
5556
public static final String ATTEMPT_TO_CREATE_A_TAG_FOR_FINISHED_HINT = "Attempt to create a tag for a hint which is already marked as finished, tag will not be created.";
5657
public static final String ATTEMPT_TO_MOVE_TO_FLUSHED_PARENT = "An attempt is made to move the tag tree pointer to the tag parent which has been already flushed. Tag tree pointer is moved to the root tag instead.";
5758
public static final String CALCULATE_HASHCODE_FOR_MODIFIED_PDFNUMBER = "Calculate hashcode for modified PdfNumber.";
@@ -126,10 +127,10 @@ public final class LogMessageConstant {
126127
public static final String MAPPING_IN_STRUCT_ROOT_OVERWRITTEN = "Existing mapping for {0} in structure tree root role map was {1} and it was overwritten with {2}.";
127128
public static final String METHOD_IS_NOT_IMPLEMENTED_BY_DEFAULT_OTHER_METHOD_WILL_BE_USED = "Method {0} is not implemented by default: please, override and implement it. {1} will be used instead.";
128129
public static final String NAME_ALREADY_EXISTS_IN_THE_NAME_TREE = "Name \"{0}\" already exists in the name tree; old value will be replaced by the new one.";
129-
public static final String N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY = "\\N entry is required to be present in an appearance dictionary.";
130130
public static final String NOT_TAGGED_PAGES_IN_TAGGED_DOCUMENT = "Not tagged pages are copied to the tagged document. Destination document now may contain not tagged content.";
131131
public static final String NO_FIELDS_IN_ACROFORM = "Required AcroForm entry /Fields does not exist in the document. Empty array /Fields will be created.";
132132
public static final String NUM_TREE_SHALL_NOT_END_WITH_KEY = "Number tree ends with a key which is invalid according to the PDF specification.";
133+
public static final String N_ENTRY_IS_REQUIRED_FOR_APPEARANCE_DICTIONARY = "\\N entry is required to be present in an appearance dictionary.";
133134
public static final String OCCUPIED_AREA_HAS_NOT_BEEN_INITIALIZED = "Occupied area has not been initialized. {0}";
134135
public static final String OCSP_STATUS_IS_REVOKED = "OCSP status is revoked.";
135136
public static final String OCSP_STATUS_IS_UNKNOWN = "OCSP status is unknown.";

io/src/main/java/com/itextpdf/io/source/ByteUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ This file is part of the iText (R) project.
4343
*/
4444
package com.itextpdf.io.source;
4545

46+
import com.itextpdf.io.LogMessageConstant;
4647
import com.itextpdf.io.util.DecimalFormatUtil;
4748

4849
import java.nio.charset.StandardCharsets;
50+
import org.slf4j.Logger;
51+
import org.slf4j.LoggerFactory;
4952

5053
public final class ByteUtils {
5154

@@ -125,6 +128,11 @@ static byte[] getIsoBytes(double d, ByteBuffer buffer) {
125128
}
126129

127130
static byte[] getIsoBytes(double d, ByteBuffer buffer, boolean highPrecision) {
131+
if (Double.isNaN(d)) {
132+
Logger logger = LoggerFactory.getLogger(ByteUtils.class);
133+
logger.error(LogMessageConstant.ATTEMPT_PROCESS_NAN);
134+
d = 0;
135+
}
128136
if (highPrecision) {
129137
if (Math.abs(d) < 0.000001) {
130138
if (buffer != null) {

io/src/test/java/com/itextpdf/io/source/WriteNumbersTest.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ This file is part of the iText (R) project.
4242
*/
4343
package com.itextpdf.io.source;
4444

45+
import com.itextpdf.io.LogMessageConstant;
4546
import com.itextpdf.io.util.DecimalFormatUtil;
47+
import com.itextpdf.test.ExtendedITextTest;
48+
import com.itextpdf.test.annotations.LogMessage;
49+
import com.itextpdf.test.annotations.LogMessages;
4650
import com.itextpdf.test.annotations.type.UnitTest;
4751

4852
import java.nio.charset.StandardCharsets;
@@ -53,14 +57,14 @@ This file is part of the iText (R) project.
5357
import org.junit.experimental.categories.Category;
5458

5559
@Category(UnitTest.class)
56-
public class WriteNumbersTest {
60+
public class WriteNumbersTest extends ExtendedITextTest {
5761

5862
public static double round(double value, int places) {
5963
return Math.round(value * Math.pow(10, places)) / Math.pow(10, places);
6064
}
6165

6266
@Test
63-
public void WriteNumber1Test() {
67+
public void writeNumber1Test() {
6468
Random rnd = new Random();
6569
for (int i = 0; i < 100000; i++) {
6670
double d = (double)rnd.nextInt(2120000000)/100000;
@@ -77,7 +81,7 @@ public void WriteNumber1Test() {
7781
}
7882

7983
@Test
80-
public void WriteNumber2Test() {
84+
public void writeNumber2Test() {
8185
Random rnd = new Random();
8286
for (int i = 0; i < 100000; i++) {
8387
double d = (double)rnd.nextInt(1000000)/1000000;
@@ -91,7 +95,7 @@ public void WriteNumber2Test() {
9195
}
9296

9397
@Test
94-
public void WriteNumber3Test() {
98+
public void writeNumber3Test() {
9599
Random rnd = new Random();
96100
for (int i = 0; i < 100000; i++) {
97101
double d = rnd.nextDouble(); if (d < 32700) d*= 100000;
@@ -102,4 +106,28 @@ public void WriteNumber3Test() {
102106
Assert.assertArrayEquals(message, expecteds, actuals);
103107
}
104108
}
109+
110+
@Test
111+
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.ATTEMPT_PROCESS_NAN))
112+
public void writeNanTest() {
113+
double d = Double.NaN;
114+
115+
byte[] actuals = ByteUtils.getIsoBytes(d);
116+
byte[] expecteds = DecimalFormatUtil.formatNumber(0, "0.##").getBytes(StandardCharsets.ISO_8859_1);
117+
118+
String message = "Expects: " + new String(expecteds) + ", actual: " + new String(actuals) + " \\\\ "+ d;
119+
Assert.assertArrayEquals(message, expecteds, actuals);
120+
}
121+
122+
@Test
123+
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.ATTEMPT_PROCESS_NAN))
124+
public void writeNanHighPrecisionTest() {
125+
double d = Double.NaN;
126+
127+
byte[] actuals = ByteUtils.getIsoBytes(d, null, true);
128+
byte[] expecteds = DecimalFormatUtil.formatNumber(0, "0.##").getBytes(StandardCharsets.ISO_8859_1);
129+
130+
String message = "Expects: " + new String(expecteds) + ", actual: " + new String(actuals) + " \\\\ "+ d;
131+
Assert.assertArrayEquals(message, expecteds, actuals);
132+
}
105133
}

kernel/src/test/java/com/itextpdf/kernel/pdf/PdfArrayTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@ This file is part of the iText (R) project.
4343
package com.itextpdf.kernel.pdf;
4444

4545
import com.itextpdf.io.source.ByteArrayOutputStream;
46+
import com.itextpdf.test.ExtendedITextTest;
4647
import com.itextpdf.test.annotations.type.UnitTest;
4748
import org.junit.Assert;
4849
import org.junit.Test;
4950
import org.junit.experimental.categories.Category;
5051

5152
@Category(UnitTest.class)
52-
public class PdfArrayTest {
53+
public class PdfArrayTest extends ExtendedITextTest {
5354

5455
@Test
5556
public void testValuesIndirectContains() {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2019 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU Affero General Public License version 3
8+
as published by the Free Software Foundation with the addition of the
9+
following permission added to Section 15 as permitted in Section 7(a):
10+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
11+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
12+
OF THIRD PARTY RIGHTS
13+
14+
This program is distributed in the hope that it will be useful, but
15+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
or FITNESS FOR A PARTICULAR PURPOSE.
17+
See the GNU Affero General Public License for more details.
18+
You should have received a copy of the GNU Affero General Public License
19+
along with this program; if not, see http://www.gnu.org/licenses or write to
20+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
22+
http://itextpdf.com/terms-of-use/
23+
24+
The interactive user interfaces in modified source and object code versions
25+
of this program must display Appropriate Legal Notices, as required under
26+
Section 5 of the GNU Affero General Public License.
27+
28+
In accordance with Section 7(b) of the GNU Affero General Public License,
29+
a covered work must retain the producer line in every PDF that is created
30+
or manipulated using iText.
31+
32+
You can be released from the requirements of the license by purchasing
33+
a commercial license. Buying such a license is mandatory as soon as you
34+
develop commercial activities involving the iText software without
35+
disclosing the source code of your own applications.
36+
These activities include: offering paid services to customers as an ASP,
37+
serving PDFs on the fly in a web application, shipping iText with a closed
38+
source product.
39+
40+
For more information, please contact iText Software Corp. at this
41+
42+
*/
43+
package com.itextpdf.kernel.pdf;
44+
45+
import com.itextpdf.io.LogMessageConstant;
46+
import com.itextpdf.test.ExtendedITextTest;
47+
import com.itextpdf.test.annotations.LogMessage;
48+
import com.itextpdf.test.annotations.LogMessages;
49+
import com.itextpdf.test.annotations.type.UnitTest;
50+
import org.junit.Assert;
51+
import org.junit.Test;
52+
import org.junit.experimental.categories.Category;
53+
54+
@Category(UnitTest.class)
55+
public class PdfNumberTest extends ExtendedITextTest {
56+
57+
@Test
58+
@LogMessages(messages = @LogMessage(messageTemplate = LogMessageConstant.ATTEMPT_PROCESS_NAN))
59+
public void testNaN() {
60+
PdfNumber number = new PdfNumber(Double.NaN);
61+
byte[] expected = {48}; // code for "0"
62+
Assert.assertArrayEquals(expected, number.getInternalContent());
63+
}
64+
}

0 commit comments

Comments
 (0)