Skip to content

Commit 21c6908

Browse files
dzmitry.kachkouiText-CI
authored andcommitted
Add check for String lengths in PDFA module
DEVSIX-2978 Autoported commit. Original commit hash: [21a86068a]
1 parent c748c2d commit 21c6908

File tree

9 files changed

+543
-18
lines changed

9 files changed

+543
-18
lines changed

itext.tests/itext.pdfa.tests/itext/pdfa/PdfALongStringTest.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ source product.
4545
using System.Text;
4646
using iText.Kernel.Font;
4747
using iText.Kernel.Pdf;
48-
using iText.Kernel.Utils;
4948
using iText.Layout;
5049
using iText.Layout.Element;
5150
using iText.Test;
@@ -69,14 +68,14 @@ public static void BeforeClass() {
6968

7069
[NUnit.Framework.Test]
7170
public virtual void RunTest() {
72-
//TODO(DEVSIX-2978): Produces non-conforming PDF/A document
73-
String file = "pdfALongString.pdf";
74-
String filename = destinationFolder + file;
75-
using (Stream icm = new FileStream(sourceFolder + "sRGB Color Space Profile.icm", FileMode.Open, FileAccess.Read
76-
)) {
77-
using (PdfADocument pdf = new PdfADocument(new PdfWriter(new FileStream(filename, FileMode.Create)), PdfAConformanceLevel
78-
.PDF_A_3U, new PdfOutputIntent("Custom", "", "http://www.color.org", "sRGB ICC preference", icm))) {
79-
using (Document document = new Document(pdf)) {
71+
NUnit.Framework.Assert.That(() => {
72+
String file = "pdfALongString.pdf";
73+
String filename = destinationFolder + file;
74+
using (Stream icm = new FileStream(sourceFolder + "sRGB Color Space Profile.icm", FileMode.Open, FileAccess.Read
75+
)) {
76+
using (Document document = new Document(new PdfADocument(new PdfWriter(new FileStream(filename, FileMode.Create
77+
)), PdfAConformanceLevel.PDF_A_3U, new PdfOutputIntent("Custom", "", "http://www.color.org", "sRGB ICC preference"
78+
, icm)))) {
8079
StringBuilder stringBuilder = new StringBuilder(LOREM_IPSUM);
8180
while (stringBuilder.Length < STRING_LENGTH_LIMIT) {
8281
stringBuilder.Append(stringBuilder.ToString());
@@ -90,8 +89,11 @@ public virtual void RunTest() {
9089
}
9190
}
9291
}
93-
NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(filename, sourceFolder + "cmp/PdfALongStringTest/cmp_"
94-
+ file, destinationFolder, "diff_"));
92+
, NUnit.Framework.Throws.InstanceOf<PdfAConformanceException>().With.Message.EqualTo(PdfAConformanceException.PDF_STRING_IS_TOO_LONG))
93+
;
9594
}
95+
// when document is auto-closing, ISO conformance check is performed
96+
// this document contain a string which is longer than it is allowed
97+
// per specification. That is why conformance exception should be thrown
9698
}
9799
}

itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA1CheckerTest.cs

Lines changed: 272 additions & 0 deletions
Large diffs are not rendered by default.

itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA2CheckerTest.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ source product.
4040
For more information, please contact iText Software Corp. at this
4141
4242
*/
43+
using System;
4344
using iText.Kernel.Pdf;
4445
using iText.Pdfa;
4546
using iText.Test;
@@ -277,6 +278,39 @@ public virtual void CheckCatalogDictionaryWithoutRequirements() {
277278
pdfA2Checker.CheckCatalogValidEntries(catalog);
278279
}
279280
, NUnit.Framework.Throws.InstanceOf<PdfAConformanceException>().With.Message.EqualTo(PdfAConformanceException.A_CATALOG_DICTIONARY_SHALL_NOT_CONTAIN_REQUIREMENTS_ENTRY))
281+
;
282+
}
283+
284+
[NUnit.Framework.Test]
285+
public virtual void IndependentLongStringTest() {
286+
NUnit.Framework.Assert.That(() => {
287+
int maxAllowedLength = pdfA2Checker.GetMaxStringLength();
288+
int testLength = maxAllowedLength + 1;
289+
NUnit.Framework.Assert.AreEqual(testLength, 32768);
290+
PdfString longString = new PdfString(PdfACheckerTestUtils.GetLongString(testLength));
291+
// An exception should be thrown as provided String is longer then
292+
// it is allowed per specification
293+
pdfA2Checker.CheckPdfObject(longString);
294+
}
295+
, NUnit.Framework.Throws.InstanceOf<PdfAConformanceException>().With.Message.EqualTo(PdfAConformanceException.PDF_STRING_IS_TOO_LONG))
296+
;
297+
}
298+
299+
[NUnit.Framework.Test]
300+
public virtual void LongStringInContentStreamTest() {
301+
NUnit.Framework.Assert.That(() => {
302+
pdfA2Checker.SetFullCheckMode(true);
303+
int maxAllowedLength = pdfA2Checker.GetMaxStringLength();
304+
int testLength = maxAllowedLength + 1;
305+
NUnit.Framework.Assert.AreEqual(testLength, 32768);
306+
String newContentString = PdfACheckerTestUtils.GetStreamWithLongString(testLength);
307+
byte[] newContent = newContentString.GetBytes(System.Text.Encoding.UTF8);
308+
PdfStream stream = new PdfStream(newContent);
309+
// An exception should be thrown as content stream has a string which
310+
// is longer then it is allowed per specification
311+
pdfA2Checker.CheckContentStream(stream);
312+
}
313+
, NUnit.Framework.Throws.InstanceOf<PdfAConformanceException>().With.Message.EqualTo(PdfAConformanceException.PDF_STRING_IS_TOO_LONG))
280314
;
281315
}
282316
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2020 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+
using System;
44+
45+
namespace iText.Pdfa.Checker {
46+
public class PdfACheckerTestUtils {
47+
private PdfACheckerTestUtils() {
48+
}
49+
50+
internal static String GetLongString(int length) {
51+
char charToFill = 'A';
52+
char[] array = new char[length];
53+
for (int i = 0; i < array.Length; i++) {
54+
array[i] = charToFill;
55+
}
56+
return new String(array);
57+
}
58+
59+
internal static String GetStreamWithLongString(int length) {
60+
return GetStreamWithValue("(" + GetLongString(length) + ")");
61+
}
62+
63+
internal static String GetStreamWithLongStringInArray(int length) {
64+
return GetStreamWithValue("[(" + GetLongString(length) + "), (a)]");
65+
}
66+
67+
internal static String GetStreamWithLongStringInDictionary(int length) {
68+
return GetStreamWithValue("<</Value (" + GetLongString(length) + ")>>");
69+
}
70+
71+
private static String GetStreamWithValue(String value) {
72+
return "q\n" + "BT\n" + "/F1 12 Tf\n" + "36 787.96 Td\n" + value + " Tj\n" + "ET\n" + "Q";
73+
}
74+
}
75+
}

itext/itext.pdfa/itext/pdfa/checker/PdfA1Checker.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ source product.
4545
using System.Collections.Generic;
4646
using Common.Logging;
4747
using iText.IO.Font;
48+
using iText.IO.Source;
4849
using iText.IO.Util;
50+
using iText.Kernel;
4951
using iText.Kernel.Colors;
5052
using iText.Kernel.Font;
5153
using iText.Kernel.Pdf;
5254
using iText.Kernel.Pdf.Annot;
5355
using iText.Kernel.Pdf.Canvas;
56+
using iText.Kernel.Pdf.Canvas.Parser.Util;
5457
using iText.Kernel.Pdf.Colorspace;
5558
using iText.Pdfa;
5659

@@ -136,6 +139,12 @@ public override void CheckColor(Color color, PdfDictionary currentColorSpaces, b
136139
public override void CheckColor(Color color, PdfDictionary currentColorSpaces, bool? fill, PdfStream stream
137140
) {
138141
CheckColorSpace(color.GetColorSpace(), currentColorSpaces, true, fill);
142+
if (color is PatternColor) {
143+
PdfPattern pattern = ((PatternColor)color).GetPattern();
144+
if (pattern is PdfPattern.Tiling) {
145+
CheckContentStream((PdfStream)pattern.GetPdfObject());
146+
}
147+
}
139148
}
140149

141150
public override void CheckColorSpace(PdfColorSpace colorSpace, PdfDictionary currentColorSpaces, bool checkAlternate
@@ -259,6 +268,57 @@ public override void CheckFont(PdfFont pdfFont) {
259268
CheckNonSymbolicTrueTypeFont(trueTypeFont);
260269
}
261270
}
271+
if (pdfFont is PdfType3Font) {
272+
PdfDictionary charProcs = pdfFont.GetPdfObject().GetAsDictionary(PdfName.CharProcs);
273+
foreach (PdfName charName in charProcs.KeySet()) {
274+
CheckContentStream(charProcs.GetAsStream(charName));
275+
}
276+
}
277+
}
278+
279+
protected internal override void CheckContentStream(PdfStream contentStream) {
280+
if (IsFullCheckMode() || contentStream.IsModified()) {
281+
byte[] contentBytes = contentStream.GetBytes();
282+
PdfTokenizer tokenizer = new PdfTokenizer(new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateSource
283+
(contentBytes)));
284+
PdfCanvasParser parser = new PdfCanvasParser(tokenizer);
285+
IList<PdfObject> operands = new List<PdfObject>();
286+
try {
287+
while (parser.Parse(operands).Count > 0) {
288+
foreach (PdfObject operand in operands) {
289+
CheckContentStreamObject(operand);
290+
}
291+
}
292+
}
293+
catch (System.IO.IOException e) {
294+
throw new PdfException(PdfException.CannotParseContentStream, e);
295+
}
296+
}
297+
}
298+
299+
protected internal override void CheckContentStreamObject(PdfObject @object) {
300+
byte type = @object.GetObjectType();
301+
switch (type) {
302+
case PdfObject.STRING: {
303+
CheckPdfString((PdfString)@object);
304+
break;
305+
}
306+
307+
case PdfObject.ARRAY: {
308+
foreach (PdfObject obj in (PdfArray)@object) {
309+
CheckContentStreamObject(obj);
310+
}
311+
break;
312+
}
313+
314+
case PdfObject.DICTIONARY: {
315+
PdfDictionary dictionary = (PdfDictionary)@object;
316+
foreach (PdfObject obj in dictionary.Values()) {
317+
CheckContentStreamObject(obj);
318+
}
319+
break;
320+
}
321+
}
262322
}
263323

264324
protected internal override void CheckNonSymbolicTrueTypeFont(PdfTrueTypeFont trueTypeFont) {
@@ -333,6 +393,7 @@ protected internal override void CheckFormXObject(PdfStream form) {
333393
);
334394
}
335395
CheckResources(form.GetAsDictionary(PdfName.Resources));
396+
CheckContentStream(form);
336397
}
337398

338399
protected internal override void CheckLogicalStructure(PdfDictionary catalog) {

itext/itext.pdfa/itext/pdfa/checker/PdfA2Checker.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,13 @@ public override void CheckColor(Color color, PdfDictionary currentColorSpaces, b
149149
CanvasGraphicsState gState = new _CanvasGraphicsState_164(extGStateDict);
150150
CheckExtGState(gState, contentStream);
151151
}
152+
else {
153+
if (pattern is PdfPattern.Tiling) {
154+
CheckContentStream((PdfStream)pattern.GetPdfObject());
155+
}
156+
}
152157
}
153-
CheckColorSpace(color.GetColorSpace(), currentColorSpaces, true, fill);
158+
base.CheckColor(color, currentColorSpaces, fill, contentStream);
154159
}
155160

156161
private sealed class _CanvasGraphicsState_164 : CanvasGraphicsState {
@@ -841,6 +846,7 @@ protected internal virtual void CheckFormXObject(PdfStream form, PdfStream conte
841846
}
842847
}
843848
CheckResources(form.GetAsDictionary(PdfName.Resources));
849+
CheckContentStream(form);
844850
}
845851

846852
private void CheckContentsForTransparency(PdfDictionary pageDict) {

0 commit comments

Comments
 (0)