Skip to content

Commit e7a1b1f

Browse files
dzmitry.kachkouiText-CI
authored andcommitted
Add check for pdf names in pdfa
DEVSIX-4048
1 parent fc5d1b2 commit e7a1b1f

File tree

5 files changed

+117
-10
lines changed

5 files changed

+117
-10
lines changed

pdfa/src/main/java/com/itextpdf/pdfa/PdfAConformanceException.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ This file is part of the iText (R) project.
5050
*/
5151
public class PdfAConformanceException extends PdfException {
5252

53-
private static final long serialVersionUID = -5951503441486657717L;
54-
5553
public static final String _0_ACTIONS_ARE_NOT_ALLOWED = "{0} actions are not allowed";
5654
public static final String A_CATALOG_DICTIONARY_SHALL_CONTAIN_METADATA_ENTRY = "A catalog dictionary shall contain metadata entry";
5755
public static final String A_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_AA_ENTRY = "A catalog dictionary shall not contain aa entry";
@@ -128,6 +126,7 @@ public class PdfAConformanceException extends PdfException {
128126
public static final String ORDER_ARRAY_SHALL_CONTAIN_REFERENCES_TO_ALL_OCGS = "Order array shall contain references to all ocgs";
129127
public static final String OUTPUT_INTENT_COLOR_SPACE_SHALL_BE_EITHER_GRAY_RGB_OR_CMYK = "Output intent color space shall be either gray rgb or cmyk";
130128
public static final String OVERPRINT_MODE_SHALL_NOT_BE_ONE_WHEN_AN_ICCBASED_CMYK_COLOUR_SPACE_IS_USED_AND_WHEN_OVERPRINTING_IS_SET_TO_TRUE = "Overprint mode shall not be one when an ICCBased CMYK colour space is used and when overprinting is set to true";
129+
public static final String PDF_NAME_IS_TOO_LONG = "PdfName is too long";
131130
public static final String PDF_STRING_IS_TOO_LONG = "PdfString is too long";
132131
public static final String PROFILE_STREAM_OF_OUTPUTINTENT_SHALL_BE_OUTPUT_PROFILE_PRTR_OR_MONITOR_PROFILE_MNTR = "Profile stream of outputintent shall be output profile (prtr) or monitor profile (mntr)";
133132
public static final String REAL_NUMBER_IS_OUT_OF_RANGE = "Real number is out of range";
@@ -153,6 +152,8 @@ public class PdfAConformanceException extends PdfException {
153152
public static final String TRANSPARENCY_IS_NOT_ALLOWED_CA_SHALL_BE_EQUAL_TO_1 = "Transparency is not allowed. CA shall be equal to 1";
154153
public static final String VALUE_OF_NAME_ENTRY_SHALL_BE_UNIQUE_AMONG_ALL_OPTIONAL_CONTENT_CONFIGURATION_DICTIONARIES = "Value of name entry shall be unique among all optional content configuration dictionaries";
155154
public static final String WIDGET_ANNOTATION_DICTIONARY_OR_FIELD_DICTIONARY_SHALL_NOT_INCLUDE_A_OR_AA_ENTRY = "Widget annotation dictionary or field dictionary shall not include a or aa entry";
155+
156+
private static final long serialVersionUID = -5951503441486657717L;
156157

157158
@Deprecated
158159
public static final String IF_THE_DOCUMENT_DOES_NOT_CONTAIN_A_PDFA_OUTPUTINTENT_TRANSPARENCY_IS_FORBIDDEN = "If the document does not contain a pdfa outputintent transparency is forbidden";

pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfA1Checker.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ protected void checkContentStream(PdfStream contentStream) {
312312
protected void checkContentStreamObject(PdfObject object) {
313313
byte type = object.getType();
314314
switch (type) {
315+
case PdfObject.NAME:
316+
checkPdfName((PdfName) object);
317+
break;
315318
case PdfObject.STRING:
316319
checkPdfString((PdfString) object);
317320
break;
@@ -328,7 +331,11 @@ protected void checkContentStreamObject(PdfObject object) {
328331
case PdfObject.DICTIONARY:
329332
PdfDictionary dictionary = (PdfDictionary) object;
330333
checkPdfDictionary(dictionary);
331-
for (PdfObject obj : dictionary.values()) {
334+
for (final PdfName name: dictionary.keySet()) {
335+
checkPdfName(name);
336+
checkPdfObject(dictionary.get(name, false));
337+
}
338+
for (final PdfObject obj : dictionary.values()) {
332339
checkContentStreamObject(obj);
333340
}
334341
break;
@@ -524,6 +531,22 @@ protected void checkPdfStream(PdfStream stream) {
524531
}
525532
}
526533

534+
@Override
535+
protected void checkPdfName(PdfName name) {
536+
if (name.getValue().length() > getMaxNameLength()) {
537+
throw new PdfAConformanceException(PdfAConformanceException.PDF_NAME_IS_TOO_LONG);
538+
}
539+
}
540+
541+
/**
542+
* Retrieve maximum allowed length of the name object.
543+
*
544+
* @return maximum allowed length of the name
545+
*/
546+
protected int getMaxNameLength() {
547+
return 127;
548+
}
549+
527550
@Override
528551
protected void checkPdfString(PdfString string) {
529552
if (string.getValueBytes().length > getMaxStringLength()) {

pdfa/src/main/java/com/itextpdf/pdfa/checker/PdfAChecker.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ public void checkSinglePage(PdfPage page) {
195195
*/
196196
public void checkPdfObject(PdfObject obj) {
197197
switch (obj.getType()) {
198+
case PdfObject.NAME:
199+
checkPdfName((PdfName) obj);
200+
break;
198201
case PdfObject.NUMBER:
199202
checkPdfNumber((PdfNumber) obj);
200203
break;
@@ -420,6 +423,7 @@ protected void checkContentStreamObject(PdfObject object) {
420423
protected abstract void checkPageSize(PdfDictionary page);
421424
protected abstract void checkPdfArray(PdfArray array);
422425
protected abstract void checkPdfDictionary(PdfDictionary dictionary);
426+
protected abstract void checkPdfName(PdfName name);
423427
protected abstract void checkPdfNumber(PdfNumber number);
424428
protected abstract void checkPdfStream(PdfStream stream);
425429
protected abstract void checkPdfString(PdfString string);
@@ -518,6 +522,7 @@ private void checkArrayRecursively(PdfArray array) {
518522

519523
private void checkDictionaryRecursively(PdfDictionary dictionary) {
520524
for (PdfName name: dictionary.keySet()) {
525+
checkPdfName(name);
521526
PdfObject object = dictionary.get(name, false);
522527
if (object != null && ! object.isIndirect()) {
523528
checkPdfObject(object);

pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfA1ImplementationLimitsCheckerTest.java

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public void before() {
9292

9393
@Test
9494
public void validObjectsTest() {
95+
final int maxNameLength = pdfA1Checker.getMaxNameLength();
9596
final int maxStringLength = pdfA1Checker.getMaxStringLength();
9697
final int maxArrayCapacity = MAX_ARRAY_CAPACITY;
9798
final int maxDictionaryCapacity = MAX_DICTIONARY_CAPACITY;
@@ -100,7 +101,9 @@ public void validObjectsTest() {
100101
final double maxRealValue = pdfA1Checker.getMaxRealValue();
101102

102103
Assert.assertEquals(65535, maxStringLength);
104+
Assert.assertEquals(127, maxNameLength);
103105
PdfString longString = PdfACheckerTestUtils.getLongString(maxStringLength);
106+
PdfName longName = PdfACheckerTestUtils.getLongName(maxNameLength);
104107

105108
PdfArray longArray = PdfACheckerTestUtils.getLongArray(maxArrayCapacity);
106109
PdfDictionary longDictionary = PdfACheckerTestUtils.getLongDictionary(maxDictionaryCapacity);
@@ -113,7 +116,7 @@ public void validObjectsTest() {
113116
PdfNumber negativeInteger = new PdfNumber(minIntegerValue);
114117
PdfNumber largeReal = new PdfNumber(maxRealValue - 0.001);
115118

116-
PdfObject[] largeObjects = {longString, longArray, longDictionary,
119+
PdfObject[] largeObjects = {longName, longString, longArray, longDictionary,
117120
largeInteger, negativeInteger, largeReal};
118121
// No exceptions should not be thrown as all values match the
119122
// limitations provided in specification
@@ -152,6 +155,18 @@ public void independentLongStringTest() {
152155
pdfA1Checker.checkPdfObject(longString);
153156
}
154157

158+
@Test
159+
public void independentLongNameTest() {
160+
junitExpectedException.expect(PdfAConformanceException.class);
161+
junitExpectedException.expectMessage(PdfAConformanceException.PDF_NAME_IS_TOO_LONG);
162+
163+
PdfName longName = buildLongName();
164+
165+
// An exception should be thrown as provided name is longer then
166+
// it is allowed per specification
167+
pdfA1Checker.checkPdfObject(longName);
168+
}
169+
155170
@Test
156171
public void independentLargeIntegerTest() {
157172
junitExpectedException.expect(PdfAConformanceException.class);
@@ -234,6 +249,23 @@ public void longStringInDictionaryTest() {
234249
checkInDictionary(longString);
235250
}
236251

252+
@Test
253+
public void longNameAsKeyInDictionaryTest() {
254+
junitExpectedException.expect(PdfAConformanceException.class);
255+
junitExpectedException.expectMessage(PdfAConformanceException.PDF_NAME_IS_TOO_LONG);
256+
257+
PdfName longName = buildLongName();
258+
259+
PdfDictionary dict = new PdfDictionary();
260+
dict.put(new PdfName("Key1"), new PdfString("value1"));
261+
dict.put(new PdfName("Key2"), new PdfString("value2"));
262+
dict.put(longName, new PdfString("value3"));
263+
264+
// An exception should be thrown as dictionary contains key which is longer then
265+
// it is allowed per specification
266+
pdfA1Checker.checkPdfObject(dict);
267+
}
268+
237269
@Test
238270
public void longStringInArrayTest() {
239271
junitExpectedException.expect(PdfAConformanceException.class);
@@ -257,6 +289,18 @@ public void longStringInContentStreamTest() {
257289
checkInContentStream(longString);
258290
}
259291

292+
@Test
293+
public void longNameInContentStreamTest() {
294+
junitExpectedException.expect(PdfAConformanceException.class);
295+
junitExpectedException.expectMessage(PdfAConformanceException.PDF_NAME_IS_TOO_LONG);
296+
297+
PdfName longName = buildLongName();
298+
299+
// An exception should be thrown as content stream has a name which
300+
// is longer then it is allowed per specification
301+
checkInContentStream(longName);
302+
}
303+
260304
@Test
261305
public void largeIntegerInContentStreamTest() {
262306
junitExpectedException.expect(PdfAConformanceException.class);
@@ -367,6 +411,23 @@ public void longStringInDictionaryInContentStreamTest() {
367411
checkInDictionaryInContentStream(longString);
368412
}
369413

414+
@Test
415+
public void longNameAsKeyInDictionaryInContentStreamTest() {
416+
junitExpectedException.expect(PdfAConformanceException.class);
417+
junitExpectedException.expectMessage(PdfAConformanceException.PDF_NAME_IS_TOO_LONG);
418+
419+
PdfName longName = buildLongName();
420+
421+
PdfDictionary dict = new PdfDictionary();
422+
dict.put(new PdfName("Key1"), new PdfString("value1"));
423+
dict.put(new PdfName("Key2"), new PdfString("value2"));
424+
dict.put(longName, new PdfString("value3"));
425+
426+
// An exception should be thrown as content stream has a string which
427+
// is longer then it is allowed per specification
428+
checkInContentStream(dict);
429+
}
430+
370431
@Test
371432
public void longStringInComplexStructureTest() {
372433

@@ -475,6 +536,15 @@ private PdfString buildLongString() {
475536
return PdfACheckerTestUtils.getLongString(testLength);
476537
}
477538

539+
private PdfName buildLongName() {
540+
541+
final int maxAllowedLength = pdfA1Checker.getMaxNameLength();
542+
final int testLength = maxAllowedLength + 1;
543+
544+
Assert.assertEquals(128, testLength);
545+
546+
return PdfACheckerTestUtils.getLongName(testLength);
547+
}
478548

479549
private PdfArray buildLongArray() {
480550

pdfa/src/test/java/com/itextpdf/pdfa/checker/PdfACheckerTestUtils.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ private PdfACheckerTestUtils() {
5757
}
5858

5959
static PdfString getLongString(int length) {
60-
final char charToFill = 'A';
61-
char[] array = new char[length];
62-
for (int i = 0; i < array.length; i++) {
63-
array[i] = charToFill;
64-
}
65-
return new PdfString(new String(array));
60+
return new PdfString(getLongPlainString(length));
61+
}
62+
63+
static PdfName getLongName(int length) {
64+
return new PdfName(getLongPlainString(length));
6665
}
6766

6867
static PdfArray getLongArray(int length) {
@@ -101,4 +100,13 @@ static String getStreamWithValue(PdfObject object) {
101100
+ "ET\n"
102101
+ "Q";
103102
}
103+
104+
private static String getLongPlainString(int length) {
105+
final char charToFill = 'A';
106+
char[] array = new char[length];
107+
for (int i = 0; i < array.length; i++) {
108+
array[i] = charToFill;
109+
}
110+
return new String(array);
111+
}
104112
}

0 commit comments

Comments
 (0)