Author: lehmi Date: Thu Feb 6 07:10:39 2025 New Revision: 1923602 URL: http://svn.apache.org/viewvc?rev=1923602&view=rev Log: PDFBOX-5945: fix SIZE entry in trailer dictionary, add test provided by Lahcen FTIH
Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java?rev=1923602&r1=1923601&r2=1923602&view=diff ============================================================================== --- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java (original) +++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java Thu Feb 6 07:10:39 2025 @@ -613,17 +613,18 @@ public class COSWriter implements ICOSVi getStandardOutput().writeEOL(); COSDictionary trailer = doc.getTrailer(); - //sort xref, needed only if object keys not regenerated - Collections.sort(getXRefEntries()); - COSWriterXRefEntry lastEntry = getXRefEntries().get( getXRefEntries().size()-1); - trailer.setLong(COSName.SIZE, lastEntry.getKey().getNumber()+1); // Only need to stay, if an incremental update will be performed if (!incrementalUpdate) { - trailer.removeItem( COSName.PREV ); + // sort xref, needed only if object keys not regenerated + Collections.sort(getXRefEntries()); + COSWriterXRefEntry lastEntry = getXRefEntries().get(getXRefEntries().size() - 1); + trailer.setLong(COSName.SIZE, lastEntry.getKey().getNumber() + 1); + trailer.removeItem(COSName.PREV); } if (!doc.isXRefStream()) { + trailer.setLong(COSName.SIZE, number + 1); trailer.removeItem( COSName.XREF_STM ); } // Remove a checksum if present Modified: pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java?rev=1923602&r1=1923601&r2=1923602&view=diff ============================================================================== --- pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java (original) +++ pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java Thu Feb 6 07:10:39 2025 @@ -16,11 +16,24 @@ */ package org.apache.pdfbox.pdfwriter; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; + +import org.apache.pdfbox.cos.COSDocument; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObjectKey; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDTextField; import org.junit.Test; public class COSWriterTest @@ -62,4 +75,91 @@ public class COSWriterTest })); doc.close(); } + + @Test + public void testPDFBox5945() throws Exception + { + byte[] input = create(); + checkTrailerSize(input); + + byte[] output = edit(input); + checkTrailerSize(output); + } + + private static void checkTrailerSize(byte[] docData) throws IOException + { + try + { + PDDocument pdDocument = PDDocument.load(docData); + COSDocument cosDocument = pdDocument.getDocument(); + long maxObjNumber = 0; + for (COSObjectKey key : cosDocument.getXrefTable().keySet()) + { + maxObjNumber = key.getNumber() > maxObjNumber ? key.getNumber() : maxObjNumber; + } + long sizeFromTrailer = cosDocument.getTrailer().getLong(COSName.SIZE); + assertEquals(maxObjNumber + 1, sizeFromTrailer); + pdDocument.close(); + } + catch (IOException exception) + { + // rethrow + throw exception; + } + } + + private static byte[] create() throws IOException + { + try + { + PDDocument pdDocument = new PDDocument(); + PDAcroForm acroForm = new PDAcroForm(pdDocument); + pdDocument.getDocumentCatalog().setAcroForm(acroForm); + PDResources resources = new PDResources(); + resources.put(COSName.getPDFName("Helv"), PDType1Font.HELVETICA); + resources.put(COSName.getPDFName("ZaDb"), PDType1Font.SYMBOL); + acroForm.setDefaultResources(resources); + PDPage page = new PDPage(PDRectangle.A4); + pdDocument.addPage(page); + PDTextField textField = new PDTextField(acroForm); + textField.setPartialName("textFieldName"); + acroForm.getFields().add(textField); + PDAnnotationWidget widget = textField.getWidgets().get(0); + widget.setPage(page); + page.getAnnotations().add(widget); + PDRectangle rectangle = new PDRectangle(10, 200, 200, 15); + widget.setRectangle(rectangle); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + pdDocument.save(out); + pdDocument.close(); + return out.toByteArray(); + } + catch (IOException exception) + { + // rethrow + throw exception; + } + } + + private static byte[] edit(byte[] input) throws IOException + { + try + { + PDDocument pdDocument = PDDocument.load(input); + PDTextField textField = (PDTextField) pdDocument.getDocumentCatalog().getAcroForm() + .getField("textFieldName"); + assertNotNull(textField); + textField.setMultiline(true); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + pdDocument.saveIncremental(out); + pdDocument.close(); + return out.toByteArray(); + } + catch(IOException exception) + { + // rethrow + throw exception; + } + } + }