Skip to content

Commit d2580ee

Browse files
IdamkinIitext-teamcity
authored andcommitted
Add API for unencrypted wrapper documents
DEVSIX-1213 Autoported commit. Original commit hash: [10795d219]
1 parent 1162e4b commit d2580ee

File tree

12 files changed

+404
-5
lines changed

12 files changed

+404
-5
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.IO;
3+
using iText.Kernel.Font;
4+
using iText.Kernel.Pdf;
5+
using iText.Kernel.Pdf.Canvas;
6+
using iText.Kernel.Pdf.Filespec;
7+
using iText.Kernel.Utils;
8+
using iText.Test;
9+
10+
namespace iText.Kernel.Crypto {
11+
public class UnencryptedWrapperTest : ExtendedITextTest {
12+
public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory
13+
+ "/test/itext/kernel/crypto/UnencryptedWrapperTest/";
14+
15+
public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
16+
.CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/UnencryptedWrapperTest/";
17+
18+
[NUnit.Framework.OneTimeSetUp]
19+
public static void BeforeClass() {
20+
CreateOrClearDestinationFolder(destinationFolder);
21+
}
22+
23+
/// <exception cref="System.IO.IOException"/>
24+
/// <exception cref="System.Exception"/>
25+
[NUnit.Framework.Test]
26+
public virtual void CreateSimpleWrapperDocumentTest() {
27+
String inPath = sourceFolder + "cmp_customEncryptedDocument.pdf";
28+
String cmpPath = sourceFolder + "cmp_simpleUnencryptedWrapper.pdf";
29+
String outPath = destinationFolder + "simpleUnencryptedWrapper.pdf";
30+
String diff = "diff_simpleUnencryptedWrapper.pdf_";
31+
PdfDocument document = new PdfDocument(new PdfWriter(outPath, new WriterProperties().SetPdfVersion(PdfVersion
32+
.PDF_2_0)));
33+
PdfFileSpec fs = PdfEncryptedPayloadFileSpecFactory.Create(document, inPath, new PdfEncryptedPayload("iText"
34+
));
35+
document.SetEncryptedPayload(fs);
36+
PdfFont font = PdfFontFactory.CreateFont();
37+
PdfCanvas canvas = new PdfCanvas(document.AddNewPage());
38+
canvas.SaveState().BeginText().MoveText(36, 750).SetFontAndSize(font, 30).ShowText("Hi! I'm wrapper document."
39+
).EndText().RestoreState();
40+
canvas.Release();
41+
document.Close();
42+
NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outPath, cmpPath, destinationFolder, diff
43+
));
44+
}
45+
46+
/// <exception cref="System.IO.IOException"/>
47+
/// <exception cref="System.Exception"/>
48+
[NUnit.Framework.Test]
49+
public virtual void ExtractCustomEncryptedDocumentTest() {
50+
String inPath = sourceFolder + "cmp_simpleUnencryptedWrapper.pdf";
51+
String cmpPath = sourceFolder + "cmp_customEncryptedDocument.pdf";
52+
String outPath = destinationFolder + "customEncryptedDocument.pdf";
53+
PdfDocument document = new PdfDocument(new PdfReader(inPath));
54+
PdfStream stream = document.GetEncryptedPayloadAsStream();
55+
byte[] encryptedDocumentBytes = stream.GetBytes();
56+
FileStream fos = new FileStream(outPath, FileMode.Create);
57+
fos.Write(encryptedDocumentBytes);
58+
fos.Dispose();
59+
document.Close();
60+
//TODO: check files by bytes
61+
NUnit.Framework.Assert.IsNotNull(encryptedDocumentBytes);
62+
}
63+
}
64+
}

itext/itext.io/itext/io/LogMessageConstant.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public sealed class LogMessageConstant {
7878

7979
public const String CLIP_ELEMENT = "Element content was clipped because some height properties are set.";
8080

81+
public const String COLLECTION_DICTIONARY_ALREADY_EXISTS_IT_WILL_BE_MODIFIED = "Collection dictionary already exists. It will be modified.";
82+
8183
public const String COLORANT_INTENSITIES_INVALID = "Some of colorant intensities are invalid: they are bigger than 1 or less than 0. We will force them to become 1 or 0 respectively.";
8284

8385
public const String COLOR_ALPHA_CHANNEL_IS_IGNORED = "Alpha channel {0} was ignored during color creation. Note that opacity can be achieved in some places by using 'setOpacity' method or 'TransparentColor' class";
@@ -104,6 +106,9 @@ public sealed class LogMessageConstant {
104106

105107
public const String ENCOUNTERED_INVALID_MCR = "Corrupted tag structure: encountered invalid marked content reference - it doesn't refer to any page or any mcid. This content reference will be ignored.";
106108

109+
public const String ENCRYPTED_PAYLOAD_FILE_SPEC_SHALL_HAVE_AFRELATIONSHIP_FILED_EQUAL_TO_ENCRYPTED_PAYLOAD
110+
= "Encrypted payload file spec shall have 'AFRelationship' filed equal to 'EncryptedPayload'";
111+
107112
public const String ENCRYPTION_ENTRIES_P_AND_ENCRYPT_METADATA_NOT_CORRESPOND_PERMS_ENTRY = "Encryption dictionary entries P and EncryptMetadata have value that does not correspond to encrypted values in Perms key.";
108113

109114
public const String EXCEPTION_WHILE_CREATING_DEFAULT_FONT = "Exception while creating default font (Helvetica, WinAnsi)";

itext/itext.kernel/itext/kernel/PdfException.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ public class PdfException : Exception {
164164

165165
public const String CannotSetDataToPdfstreamWhichWasCreatedByInputStream = "Cannot set data to PdfStream which was created by InputStream.";
166166

167+
public const String CannotSetEncryptedPayloadToDocumentOpenedInReadingMode = "Cannot set encrypted payload to a document opened in read only mode.";
168+
169+
public const String CannotSetEncryptedPayloadToEncryptedDocument = "Cannot set encrypted payload to an encrypted document.";
170+
167171
public const String CannotSplitDocumentThatIsBeingWritten = "Cannot split document that is being written.";
168172

169173
public const String CannotWriteToPdfStream = "Cannot write to PdfStream.";
@@ -216,6 +220,14 @@ public class PdfException : Exception {
216220

217221
public const String ErrorWhileReadingObjectStream = "Error while reading Object Stream.";
218222

223+
public const String EncryptedPayloadFileSpecDoesntHaveCorrectEncryptedPayloadDictionary = "Encrypted payload file spec shall have encrypted payload dictionary with 'Subtype' specifying crypto filter and with 'Type' equal to 'EncryptedPayload' if present";
224+
225+
public const String EncryptedPayloadFileSpecShallBeIndirect = "Encrypted payload file spec shall be indirect.";
226+
227+
public const String EncryptedPayloadFileSpecShallHaveEFDictionary = "Encrypted payload file spec shall have 'EF' key. The value of such key shall be a dictionary that contains embedded file stream.";
228+
229+
public const String EncryptedPayloadFileSpecShallHaveTypeEqualToFilespec = "Encrypted payload file spec shall have 'Type' key. The value of such key shall be 'Filespec'.";
230+
219231
public const String FailedToGetTsaResponseFrom1 = "Failed to get TSA response from {0}.";
220232

221233
public const String FieldFlatteningIsNotSupportedInAppendMode = "Field flattening is not supported in append mode.";

itext/itext.kernel/itext/kernel/pdf/PdfCatalog.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ public virtual void AddDeveloperExtension(PdfDeveloperExtension extension) {
283283
extensions.Put(extension.GetPrefix(), extension.GetDeveloperExtensions());
284284
}
285285

286+
/// <summary>
287+
/// Gets collection dictionary that a conforming reader shall use to enhance the presentation of file attachments
288+
/// stored in the PDF document.
289+
/// </summary>
290+
/// <returns>
291+
///
292+
/// <see cref="iText.Kernel.Pdf.Collection.PdfCollection"/>
293+
/// wrapper of collection dictionary.
294+
/// </returns>
295+
public virtual PdfCollection GetCollection() {
296+
PdfDictionary collectionDictionary = GetPdfObject().GetAsDictionary(PdfName.Collection);
297+
if (collectionDictionary != null) {
298+
return new PdfCollection(collectionDictionary);
299+
}
300+
return null;
301+
}
302+
286303
/// <summary>
287304
/// Sets collection dictionary that a conforming reader shall use to enhance the presentation of file attachments
288305
/// stored in the PDF document.

itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ source product.
5656
using iText.Kernel.Numbering;
5757
using iText.Kernel.Pdf.Annot;
5858
using iText.Kernel.Pdf.Canvas;
59+
using iText.Kernel.Pdf.Collection;
5960
using iText.Kernel.Pdf.Filespec;
6061
using iText.Kernel.Pdf.Navigation;
6162
using iText.Kernel.Pdf.Tagging;
@@ -214,8 +215,7 @@ public PdfDocument(PdfReader reader, PdfWriter writer, StampingProperties proper
214215
this.reader = reader;
215216
this.writer = writer;
216217
this.properties = properties;
217-
bool writerHasEncryption = writer.properties.IsStandardEncryptionUsed() || writer.properties.IsPublicKeyEncryptionUsed
218-
();
218+
bool writerHasEncryption = WriterHasEncryption();
219219
if (properties.appendMode && writerHasEncryption) {
220220
ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.PdfDocument));
221221
logger.Warn(iText.IO.LogMessageConstant.WRITER_ENCRYPTION_IS_IGNORED_APPEND);
@@ -1432,6 +1432,75 @@ public virtual PdfArray GetAssociatedFiles() {
14321432
return catalog.GetPdfObject().GetAsArray(PdfName.AF);
14331433
}
14341434

1435+
/// <summary>
1436+
/// Gets the encrypted payload of this document,
1437+
/// or returns
1438+
/// <see langword="null"/>
1439+
/// if this document isn't an unencrypted wrapper document.
1440+
/// </summary>
1441+
/// <returns>encrypted payload of this document.</returns>
1442+
public virtual PdfStream GetEncryptedPayloadAsStream() {
1443+
if (GetReader() != null && GetReader().IsEncrypted()) {
1444+
return null;
1445+
}
1446+
PdfCollection collection = GetCatalog().GetCollection();
1447+
if (collection != null && PdfName.H.Equals(collection.GetView())) {
1448+
PdfString documentName = collection.GetInitialDocument();
1449+
PdfNameTree embeddedFiles = GetCatalog().GetNameTree(PdfName.EmbeddedFiles);
1450+
PdfObject fileSpecObject = embeddedFiles.GetNames().Get(documentName.ToUnicodeString());
1451+
if (fileSpecObject != null && fileSpecObject.IsDictionary()) {
1452+
PdfFileSpec fileSpec = PdfEncryptedPayloadFileSpecFactory.Wrap((PdfDictionary)fileSpecObject);
1453+
if (fileSpec != null) {
1454+
PdfDictionary embeddedDictionary = ((PdfDictionary)fileSpec.GetPdfObject()).GetAsDictionary(PdfName.EF);
1455+
PdfStream uf = embeddedDictionary.GetAsStream(PdfName.UF);
1456+
return uf != null ? uf : embeddedDictionary.GetAsStream(PdfName.F);
1457+
}
1458+
}
1459+
}
1460+
return null;
1461+
}
1462+
1463+
/// <summary>Sets an encrypted payload, making this document an unencrypted wrapper document.</summary>
1464+
/// <remarks>
1465+
/// Sets an encrypted payload, making this document an unencrypted wrapper document.
1466+
/// The file spec shall include the AFRelationship key with a value of EncryptedPayload,
1467+
/// and shall include an encrypted payload dictionary.
1468+
/// </remarks>
1469+
/// <param name="fs">
1470+
/// encrypted payload file spec.
1471+
/// <see cref="iText.Kernel.Pdf.Filespec.PdfEncryptedPayloadFileSpecFactory"/>
1472+
/// can produce one.
1473+
/// </param>
1474+
public virtual void SetEncryptedPayload(PdfFileSpec fs) {
1475+
if (GetWriter() == null) {
1476+
throw new PdfException(PdfException.CannotSetEncryptedPayloadToDocumentOpenedInReadingMode);
1477+
}
1478+
if (WriterHasEncryption()) {
1479+
throw new PdfException(PdfException.CannotSetEncryptedPayloadToEncryptedDocument);
1480+
}
1481+
if (!PdfName.EncryptedPayload.Equals(((PdfDictionary)fs.GetPdfObject()).Get(PdfName.AFRelationship))) {
1482+
LogManager.GetLogger(GetType()).Error(iText.IO.LogMessageConstant.ENCRYPTED_PAYLOAD_FILE_SPEC_SHALL_HAVE_AFRELATIONSHIP_FILED_EQUAL_TO_ENCRYPTED_PAYLOAD
1483+
);
1484+
}
1485+
PdfEncryptedPayload encryptedPayload = PdfEncryptedPayload.ExtractFrom(fs);
1486+
if (encryptedPayload == null) {
1487+
throw new PdfException(PdfException.EncryptedPayloadFileSpecDoesntHaveCorrectEncryptedPayloadDictionary);
1488+
}
1489+
PdfCollection collection = GetCatalog().GetCollection();
1490+
if (collection != null) {
1491+
LogManager.GetLogger(GetType()).Warn(iText.IO.LogMessageConstant.COLLECTION_DICTIONARY_ALREADY_EXISTS_IT_WILL_BE_MODIFIED
1492+
);
1493+
}
1494+
else {
1495+
collection = new PdfCollection();
1496+
GetCatalog().SetCollection(collection);
1497+
}
1498+
collection.SetView(PdfCollection.HIDDEN);
1499+
String displayName = PdfEncryptedPayloadFileSpecFactory.GenerateFileDisplay(encryptedPayload);
1500+
collection.SetInitialDocument(displayName);
1501+
AddAssociatedFile(displayName, fs);
1502+
}
1503+
14351504
/// <summary>This method retrieves the page labels from a document as an array of String objects.</summary>
14361505
/// <returns>
14371506
///
@@ -2148,6 +2217,10 @@ private long GetDocumentId() {
21482217
return documentId;
21492218
}
21502219

2220+
private bool WriterHasEncryption() {
2221+
return writer.properties.IsStandardEncryptionUsed() || writer.properties.IsPublicKeyEncryptionUsed();
2222+
}
2223+
21512224
/// <summary>A structure storing documentId, object number and generation number.</summary>
21522225
/// <remarks>
21532226
/// A structure storing documentId, object number and generation number. This structure is using to calculate
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using iText.Kernel.Pdf.Filespec;
3+
4+
namespace iText.Kernel.Pdf {
5+
public class PdfEncryptedPayload : PdfObjectWrapper<PdfDictionary> {
6+
public PdfEncryptedPayload(String subtype)
7+
: this(new PdfDictionary()) {
8+
GetPdfObject().Put(PdfName.Type, PdfName.EncryptedPayload);
9+
SetSubtype(subtype);
10+
}
11+
12+
private PdfEncryptedPayload(PdfDictionary pdfObject)
13+
: base(pdfObject) {
14+
}
15+
16+
public static iText.Kernel.Pdf.PdfEncryptedPayload ExtractFrom(PdfFileSpec fileSpec) {
17+
if (fileSpec.GetPdfObject().IsDictionary()) {
18+
return iText.Kernel.Pdf.PdfEncryptedPayload.Wrap(((PdfDictionary)fileSpec.GetPdfObject()).GetAsDictionary(
19+
PdfName.EP));
20+
}
21+
return null;
22+
}
23+
24+
public static iText.Kernel.Pdf.PdfEncryptedPayload Wrap(PdfDictionary dictionary) {
25+
PdfName type = dictionary.GetAsName(PdfName.Type);
26+
if (type == null || type.Equals(PdfName.EncryptedPayload)) {
27+
if (dictionary.GetAsName(PdfName.Subtype) != null) {
28+
return new iText.Kernel.Pdf.PdfEncryptedPayload(dictionary);
29+
}
30+
}
31+
return null;
32+
}
33+
34+
public virtual PdfName GetSubtype() {
35+
return GetPdfObject().GetAsName(PdfName.Subtype);
36+
}
37+
38+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetSubtype(String subtype) {
39+
return SetSubtype(new PdfName(subtype));
40+
}
41+
42+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetSubtype(PdfName subtype) {
43+
SetModified();
44+
GetPdfObject().Put(PdfName.Subtype, subtype);
45+
return this;
46+
}
47+
48+
public virtual PdfName GetVersion() {
49+
return GetPdfObject().GetAsName(PdfName.Version);
50+
}
51+
52+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetVersion(String version) {
53+
return SetVersion(new PdfName(version));
54+
}
55+
56+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetVersion(PdfName version) {
57+
SetModified();
58+
GetPdfObject().Put(PdfName.Version, version);
59+
return this;
60+
}
61+
62+
protected internal override bool IsWrappedObjectMustBeIndirect() {
63+
return false;
64+
}
65+
}
66+
}

itext/itext.kernel/itext/kernel/pdf/PdfName.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ public class PdfName : PdfPrimitiveObject, IComparable<iText.Kernel.Pdf.PdfName>
562562

563563
public static readonly iText.Kernel.Pdf.PdfName Enforce = CreateDirectName("Enforce");
564564

565+
public static readonly iText.Kernel.Pdf.PdfName EP = CreateDirectName("EP");
566+
565567
public static readonly iText.Kernel.Pdf.PdfName ESIC = CreateDirectName("ESIC");
566568

567569
public static readonly iText.Kernel.Pdf.PdfName ETSI_CAdES_DETACHED = CreateDirectName("ETSI.CAdES.detached"

itext/itext.kernel/itext/kernel/pdf/collection/PdfCollection.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ public virtual iText.Kernel.Pdf.Collection.PdfCollection SetView(int viewType) {
111111
return this;
112112
}
113113

114-
public virtual PdfNumber GetView() {
115-
return GetPdfObject().GetAsNumber(PdfName.View);
114+
//TODO is it ok to break backwards compatibility?
115+
public virtual PdfName GetView() {
116+
return GetPdfObject().GetAsName(PdfName.View);
116117
}
117118

118119
/// <summary>Sets the Collection sort dictionary.</summary>

0 commit comments

Comments
 (0)