Skip to content

Commit ccaa218

Browse files
Merge branch 'hotfix/xref_free_refs' into develop
2 parents 4496899 + 12f32dd commit ccaa218

File tree

15 files changed

+501
-55
lines changed

15 files changed

+501
-55
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfDocument.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -800,12 +800,14 @@ public void close() {
800800
flushFonts();
801801
writer.flushWaitingObjects();
802802
// flush unused objects
803-
if (isFlushUnusedObjects()) {
804-
for (int i = 0; i < xref.size(); i++) {
805-
PdfIndirectReference indirectReference = xref.get(i);
806-
if (!indirectReference.isFree() && !indirectReference.checkState(PdfObject.FLUSHED)) {
803+
for (int i = 0; i < xref.size(); i++) {
804+
PdfIndirectReference indirectReference = xref.get(i);
805+
if (indirectReference != null && !indirectReference.isFree() && !indirectReference.checkState(PdfObject.FLUSHED)) {
806+
if (isFlushUnusedObjects() && !indirectReference.checkState(PdfObject.ORIGINAL_OBJECT_STREAM)) {
807807
PdfObject object = indirectReference.getRefersTo();
808808
object.flush();
809+
} else {
810+
indirectReference.setFree();
809811
}
810812
}
811813
}

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfIndirectReference.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,8 @@ protected PdfReader getReader() {
265265
return null;
266266
}
267267

268-
// NOTE In append mode object could be OriginalObjectStream, but not Modified,
269-
// so information about this reference would not be added to the new Cross-Reference table.
270-
// In stamp mode without append the reference will be free.
271268
protected boolean isFree() {
272-
return checkState(FREE) || checkState(ORIGINAL_OBJECT_STREAM);
269+
return checkState(FREE);
273270
}
274271

275272
@Override

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ protected PdfDictionary readXrefSection() throws IOException {
841841
}
842842
} else if (tokens.tokenValueEqualsTo(PdfTokenizer.F)) {
843843
if (xref.get(num) == null) {
844-
reference.setFree();
844+
xref.freeReference(reference, true);
845845
xref.add(reference);
846846
}
847847
} else

kernel/src/main/java/com/itextpdf/kernel/pdf/PdfXrefTable.java

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ This file is part of the iText (R) project.
4444
package com.itextpdf.kernel.pdf;
4545

4646
import com.itextpdf.io.source.ByteUtils;
47-
import com.itextpdf.io.util.DecimalFormatUtil;
48-
import com.itextpdf.kernel.PdfException;
4947
import com.itextpdf.kernel.Version;
5048

5149
import java.io.IOException;
@@ -68,7 +66,7 @@ class PdfXrefTable implements Serializable {
6866
private PdfIndirectReference[] xref;
6967
private int count = 0;
7068

71-
private final TreeSet<Integer> freeReferences;
69+
private final TreeSet<Integer> freeReferences; // TODO not using this collection for now
7270

7371
public PdfXrefTable() {
7472
this(INITIAL_CAPACITY);
@@ -116,20 +114,8 @@ public PdfIndirectReference get(int index) {
116114
* @return created indirect reference.
117115
*/
118116
protected PdfIndirectReference createNextIndirectReference(PdfDocument document) {
119-
PdfIndirectReference reference;
120-
if (freeReferences.size() > 0) {
121-
int num = (int) freeReferences.pollFirst();
122-
reference = xref[num];
123-
if (reference == null) {
124-
reference = new PdfIndirectReference(document, num);
125-
xref[num] = reference;
126-
}
127-
reference.setOffset(0);
128-
reference.clearState(PdfObject.FREE);
129-
} else {
130-
reference = new PdfIndirectReference(document, ++count);
131-
add(reference);
132-
}
117+
PdfIndirectReference reference = new PdfIndirectReference(document, ++count);
118+
add(reference);
133119
return reference.setState(PdfObject.MODIFIED);
134120
}
135121

@@ -141,19 +127,20 @@ PdfIndirectReference createNewIndirectReference(PdfDocument document) {
141127
}
142128

143129
protected void freeReference(PdfIndirectReference reference) {
130+
freeReference(reference, false);
131+
}
132+
133+
void freeReference(PdfIndirectReference reference, boolean readingFreeReference) {
144134
reference.setOffset(0);
145135
reference.setState(PdfObject.FREE);
146136
if (!reference.checkState(PdfObject.FLUSHED)) {
147137
if (reference.refersTo != null) {
148138
reference.refersTo.setIndirectReference(null).setState(PdfObject.MUST_BE_INDIRECT);
149139
reference.refersTo = null;
150140
}
151-
if (reference.getGenNumber() < MAX_GENERATION) {
152-
freeReferences.add(reference.getObjNumber());
153-
ensureCount(Math.max(this.count, reference.getObjNumber()));
154-
xref[reference.getObjNumber()] = null;
155-
}
156-
141+
}
142+
if (!readingFreeReference && reference.getGenNumber() < MAX_GENERATION) {
143+
reference.genNr++;
157144
}
158145
}
159146

@@ -170,18 +157,6 @@ protected void setCapacity(int capacity) {
170157
*/
171158
protected void writeXrefTableAndTrailer(PdfDocument document, PdfObject fileId, PdfObject crypto) throws IOException {
172159
PdfWriter writer = document.getWriter();
173-
if (document.isAppendMode()) {
174-
// Increment generation number for all freed references.
175-
for (Integer objNr : freeReferences) {
176-
xref[(int) objNr].genNr++;
177-
}
178-
} else {
179-
for (Integer objNr : freeReferences) {
180-
xref[(int) objNr] = null;
181-
}
182-
}
183-
freeReferences.clear();
184-
185160

186161
for (int i = count; i > 0; --i) {
187162
PdfIndirectReference lastRef = xref[i];
@@ -195,19 +170,27 @@ protected void writeXrefTableAndTrailer(PdfDocument document, PdfObject fileId,
195170
}
196171
}
197172

173+
int lastFreeObjNr = 0;
174+
for (int i = count; i >= 0; --i) {
175+
PdfIndirectReference ref = xref[i];
176+
if (ref == null) {
177+
ref = new PdfIndirectReference(document, i, 0).setState(PdfObject.FREE);
178+
xref[i] = ref;
179+
}
180+
if (ref.isFree()) {
181+
ref.setOffset(lastFreeObjNr);
182+
lastFreeObjNr = i;
183+
}
184+
}
185+
198186
List<Integer> sections = new ArrayList<>();
199187
int first = 0;
200188
int len = 1;
201-
if (document.isAppendMode()) {
202-
first = 1;
203-
len = 0;
204-
}
205189
for (int i = 1; i < size(); i++) {
206190
PdfIndirectReference reference = xref[i];
207191
if (reference != null) {
208-
if ((document.properties.appendMode && !reference.checkState(PdfObject.MODIFIED)) ||
209-
(reference.isFree() && reference.getGenNumber() == 0) ||
210-
(!reference.checkState(PdfObject.FLUSHED))) {
192+
if (document.properties.appendMode && !reference.checkState(PdfObject.MODIFIED)
193+
&& !reference.isFree()) {
211194
reference = null;
212195
}
213196
}
@@ -231,7 +214,8 @@ protected void writeXrefTableAndTrailer(PdfDocument document, PdfObject fileId,
231214
sections.add(first);
232215
sections.add(len);
233216
}
234-
if (document.properties.appendMode && sections.size() == 0) { // no modifications.
217+
if (document.properties.appendMode && sections.size() == 2
218+
&& sections.get(1) == 1) { // no modifications.
235219
xref = null;
236220
return;
237221
}
@@ -273,7 +257,8 @@ protected void writeXrefTableAndTrailer(PdfDocument document, PdfObject fileId,
273257
if (reference.isFree()) {
274258
xrefStream.getOutputStream().write(0);
275259
//NOTE The object number of the next free object should be at this position due to spec.
276-
xrefStream.getOutputStream().write(intToBytes(0));
260+
assert reference.getOffset() < Integer.MAX_VALUE;
261+
xrefStream.getOutputStream().write(intToBytes((int) reference.getOffset()));
277262
xrefStream.getOutputStream().write(shortToBytes(reference.getGenNumber()));
278263
} else if (reference.getObjStreamNumber() == 0) {
279264
xrefStream.getOutputStream().write(1);

0 commit comments

Comments
 (0)