Skip to content

Commit 891ec78

Browse files
yulian-gaponenkoitext-teamcity
authored andcommitted
Merge branch 'hotfix/xref_sections' into hotfix/xref_free_refs
Autoported commit. Original commit hash: [92f713311]
2 parents b62be3a + cf6ae32 commit 891ec78

File tree

7 files changed

+138
-39
lines changed

7 files changed

+138
-39
lines changed

itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfPagesTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public virtual void RandomObjectPagesTest() {
162162
PdfPage testPage = document.RemovePage(1000);
163163
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference() == null);
164164
document.AddPage(1000, testPage);
165-
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference().GetObjNumber() < xrefSize);
165+
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference().GetObjNumber() == xrefSize);
166166
for (int i = 0; i < pages.Length; i++) {
167167
NUnit.Framework.Assert.AreEqual(true, document.RemovePage(pages[i]), "Remove page");
168168
document.AddPage(i + 1, pages[i]);

itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfReaderTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public virtual void PagesTest01() {
315315
PdfPage testPage = document.RemovePage(1000);
316316
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference() == null);
317317
document.AddPage(1000, testPage);
318-
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference().GetObjNumber() < xrefSize);
318+
NUnit.Framework.Assert.IsTrue(testPage.GetPdfObject().GetIndirectReference().GetObjNumber() == xrefSize);
319319
for (int i = 1; i < document.GetNumberOfPages() + 1; i++) {
320320
PdfPage page = document.GetPage(i);
321321
String content = iText.IO.Util.JavaUtil.GetStringForBytes(page.GetContentStream(0).GetBytes());
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* To change this license header, choose License Headers in Project Properties.
3+
* To change this template file, choose Tools | Templates
4+
* and open the template in the editor.
5+
*/
6+
using System;
7+
using iText.Test;
8+
9+
namespace iText.Kernel.Pdf {
10+
/// <author>benoit</author>
11+
public class PdfXrefTableTest : ExtendedITextTest {
12+
public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
13+
.CurrentContext.TestDirectory) + "/resources/itext/kernel/pdf/PdfXrefTableTest/";
14+
15+
public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory
16+
+ "/test/itext/kernel/pdf/PdfXrefTableTest/";
17+
18+
[NUnit.Framework.OneTimeSetUp]
19+
public static void BeforeClass() {
20+
ITextTest.CreateOrClearDestinationFolder(destinationFolder);
21+
}
22+
23+
/// <exception cref="System.IO.IOException"/>
24+
[NUnit.Framework.Test]
25+
public virtual void TestCreateAndUpdateXMP() {
26+
String created = destinationFolder + "testCreateAndUpdateXMP_create.pdf";
27+
String updated = destinationFolder + "testCreateAndUpdateXMP_update.pdf";
28+
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(created));
29+
pdfDocument.AddNewPage();
30+
pdfDocument.GetXmpMetadata(true);
31+
// create XMP metadata
32+
pdfDocument.Close();
33+
pdfDocument = new PdfDocument(new PdfReader(created), new PdfWriter(updated));
34+
pdfDocument.Close();
35+
pdfDocument = new PdfDocument(new PdfReader(updated));
36+
PdfXrefTable xref = pdfDocument.GetXref();
37+
PdfIndirectReference freeRef = xref.Get(xref.Size() - 2);
38+
// 6
39+
/*
40+
Current xref structure:
41+
xref
42+
0 8
43+
0000000006 65535 f % this is object 0; 6 refers to free object 6
44+
0000000203 00000 n
45+
0000000510 00000 n
46+
0000000263 00000 n
47+
0000000088 00000 n
48+
0000000015 00000 n
49+
0000000000 00001 f % this is object 6; 0 refers to free object 0; note generation number
50+
0000000561 00000 n
51+
*/
52+
NUnit.Framework.Assert.IsTrue(freeRef.IsFree());
53+
NUnit.Framework.Assert.AreEqual(xref.Get(0).offsetOrIndex, freeRef.objNr);
54+
NUnit.Framework.Assert.AreEqual(1, freeRef.genNr);
55+
pdfDocument.Close();
56+
}
57+
58+
/// <exception cref="System.IO.IOException"/>
59+
[NUnit.Framework.Test]
60+
public virtual void TestCreateAndUpdateTwiceXMP() {
61+
String created = destinationFolder + "testCreateAndUpdateTwiceXMP_create.pdf";
62+
String updated = destinationFolder + "testCreateAndUpdateTwiceXMP_update.pdf";
63+
String updatedAgain = destinationFolder + "testCreateAndUpdateTwiceXMP_updatedAgain.pdf";
64+
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(created));
65+
pdfDocument.AddNewPage();
66+
pdfDocument.GetXmpMetadata(true);
67+
// create XMP metadata
68+
pdfDocument.Close();
69+
pdfDocument = new PdfDocument(new PdfReader(created), new PdfWriter(updated));
70+
pdfDocument.Close();
71+
pdfDocument = new PdfDocument(new PdfReader(updated), new PdfWriter(updatedAgain));
72+
pdfDocument.Close();
73+
pdfDocument = new PdfDocument(new PdfReader(updatedAgain));
74+
PdfXrefTable xref = pdfDocument.GetXref();
75+
PdfIndirectReference freeRef1 = xref.Get(xref.Size() - 3);
76+
// 6
77+
PdfIndirectReference freeRef2 = xref.Get(xref.Size() - 2);
78+
// 7
79+
/*
80+
Current xref structure:
81+
xref
82+
0 9
83+
0000000006 65535 f % this is object 0; 6 refers to free object 6
84+
0000000203 00000 n
85+
0000000510 00000 n
86+
0000000263 00000 n
87+
0000000088 00000 n
88+
0000000015 00000 n
89+
0000000007 00002 f % this is object 6; 7 refers to free object 7; note generation number
90+
0000000000 00001 f % this is object 7; 0 refers to free object 0; note generation number
91+
0000000561 00000 n
92+
*/
93+
NUnit.Framework.Assert.IsTrue(freeRef1.IsFree());
94+
NUnit.Framework.Assert.AreEqual(xref.Get(0).offsetOrIndex, freeRef1.objNr);
95+
NUnit.Framework.Assert.AreEqual(2, freeRef1.genNr);
96+
NUnit.Framework.Assert.IsTrue(freeRef2.IsFree());
97+
NUnit.Framework.Assert.AreEqual(freeRef1.offsetOrIndex, freeRef2.objNr);
98+
NUnit.Framework.Assert.AreEqual(1, freeRef2.genNr);
99+
pdfDocument.Close();
100+
}
101+
}
102+
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -710,13 +710,17 @@ public virtual void Close() {
710710
FlushFonts();
711711
writer.FlushWaitingObjects();
712712
// flush unused objects
713-
if (IsFlushUnusedObjects()) {
714-
for (int i = 0; i < xref.Size(); i++) {
715-
PdfIndirectReference indirectReference = xref.Get(i);
716-
if (!indirectReference.IsFree() && !indirectReference.CheckState(PdfObject.FLUSHED)) {
713+
for (int i = 0; i < xref.Size(); i++) {
714+
PdfIndirectReference indirectReference = xref.Get(i);
715+
if (indirectReference != null && !indirectReference.IsFree() && !indirectReference.CheckState(PdfObject.FLUSHED
716+
)) {
717+
if (IsFlushUnusedObjects()) {
717718
PdfObject @object = indirectReference.GetRefersTo();
718719
@object.Flush();
719720
}
721+
else {
722+
indirectReference.SetFree();
723+
}
720724
}
721725
}
722726
}

itext/itext.kernel/itext/kernel/pdf/PdfReader.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,12 @@ protected internal virtual PdfDictionary ReadXrefSection() {
917917
reference.ClearState(PdfObject.READING);
918918
}
919919
else {
920-
continue;
920+
if (reference.objNr == 0 && pos != 0L) {
921+
reference.SetIndex(pos);
922+
}
923+
else {
924+
continue;
925+
}
921926
}
922927
}
923928
if (tokens.TokenValueEqualsTo(PdfTokenizer.N)) {

itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,8 @@ public virtual PdfIndirectReference Get(int index) {
103103
/// <summary>Creates next available indirect reference.</summary>
104104
/// <returns>created indirect reference.</returns>
105105
protected internal virtual PdfIndirectReference CreateNextIndirectReference(PdfDocument document) {
106-
PdfIndirectReference reference;
107-
if (freeReferences.Count > 0) {
108-
int num = (int)freeReferences.PollFirst();
109-
reference = xref[num];
110-
if (reference == null) {
111-
reference = new PdfIndirectReference(document, num);
112-
xref[num] = reference;
113-
}
114-
reference.SetOffset(0);
115-
reference.ClearState(PdfObject.FREE);
116-
}
117-
else {
118-
reference = new PdfIndirectReference(document, ++count);
119-
Add(reference);
120-
}
106+
PdfIndirectReference reference = new PdfIndirectReference(document, ++count);
107+
Add(reference);
121108
return ((PdfIndirectReference)reference.SetState(PdfObject.MODIFIED));
122109
}
123110

@@ -129,7 +116,6 @@ internal virtual PdfIndirectReference CreateNewIndirectReference(PdfDocument doc
129116
}
130117

131118
protected internal virtual void FreeReference(PdfIndirectReference reference) {
132-
reference.SetOffset(0);
133119
reference.SetState(PdfObject.FREE);
134120
if (!reference.CheckState(PdfObject.FLUSHED)) {
135121
if (reference.refersTo != null) {
@@ -139,7 +125,6 @@ protected internal virtual void FreeReference(PdfIndirectReference reference) {
139125
if (reference.GetGenNumber() < MAX_GENERATION) {
140126
freeReferences.Add(reference.GetObjNumber());
141127
EnsureCount(Math.Max(this.count, reference.GetObjNumber()));
142-
xref[reference.GetObjNumber()] = null;
143128
}
144129
}
145130
}
@@ -155,18 +140,10 @@ protected internal virtual void SetCapacity(int capacity) {
155140
protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, PdfObject fileId, PdfObject
156141
crypto) {
157142
PdfWriter writer = document.GetWriter();
158-
if (document.IsAppendMode()) {
159-
// Increment generation number for all freed references.
160-
foreach (int? objNr in freeReferences) {
161-
xref[(int)objNr].genNr++;
162-
}
143+
// Increment generation number for all freed references.
144+
foreach (int? objNr in freeReferences) {
145+
xref[(int)objNr].genNr++;
163146
}
164-
else {
165-
foreach (int? objNr in freeReferences) {
166-
xref[(int)objNr] = null;
167-
}
168-
}
169-
freeReferences.Clear();
170147
for (int i = count; i > 0; --i) {
171148
PdfIndirectReference lastRef = xref[i];
172149
if (lastRef == null || (lastRef.IsFree() && lastRef.GetGenNumber() == 0) || (!lastRef.CheckState(PdfObject
@@ -187,8 +164,7 @@ protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, P
187164
for (int i = 1; i < Size(); i++) {
188165
PdfIndirectReference reference = xref[i];
189166
if (reference != null) {
190-
if ((document.properties.appendMode && !reference.CheckState(PdfObject.MODIFIED)) || (reference.IsFree() &&
191-
reference.GetGenNumber() == 0) || (!reference.CheckState(PdfObject.FLUSHED))) {
167+
if (document.properties.appendMode && !reference.CheckState(PdfObject.MODIFIED)) {
192168
reference = null;
193169
}
194170
}
@@ -285,7 +261,18 @@ protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, P
285261
writer.WriteInteger(first).WriteSpace().WriteInteger(len).WriteByte((byte)'\n');
286262
for (int i = first; i < first + len; i++) {
287263
PdfIndirectReference reference = xrefTable.Get(i);
288-
StringBuilder off = new StringBuilder("0000000000").Append(reference.GetOffset());
264+
StringBuilder off = new StringBuilder("0000000000");
265+
if (reference.IsFree()) {
266+
if (!freeReferences.IsEmpty()) {
267+
off.Append(freeReferences.PollFirst());
268+
}
269+
}
270+
else {
271+
/* if (freeReferences.isEmpty()), then we are at the
272+
last free reference. Its referral value must be object 0.
273+
*/
274+
off.Append(reference.GetOffset());
275+
}
289276
StringBuilder gen = new StringBuilder("00000").Append(reference.GetGenNumber());
290277
writer.WriteString(off.JSubstring(off.Length - 10, off.Length)).WriteSpace().WriteString(gen.JSubstring(gen
291278
.Length - 5, gen.Length)).WriteSpace();
@@ -316,6 +303,7 @@ protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, P
316303
writer.Write(document.GetTrailer());
317304
writer.Write('\n');
318305
}
306+
freeReferences.Clear();
319307
WriteKeyInfo(writer);
320308
writer.WriteString("startxref\n").WriteLong(startxref).WriteString("\n%%EOF\n");
321309
xref = null;

port-hash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a9e869592c56bb12a0afe24aff383a3f590da3fb
1+
92f713311a203b6af3ff544ee8e0e76df8ab1f50

0 commit comments

Comments
 (0)