You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2020/11/22 13:55:51 UTC

svn commit: r1883723 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/pdfparser/ main/java/org/apache/pdfbox/pdfparser/xref/ main/java/org/apache/pdfbox/pdfwriter/ test/java/org/apache/pdfbox/pdfwriter/

Author: lehmi
Date: Sun Nov 22 13:55:51 2020
New Revision: 1883723

URL: http://svn.apache.org/viewvc?rev=1883723&view=rev
Log:
PDFBOX-4952: replace COSWriterXRefEntry with separated classes as proposed by Christian Appl

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java   (with props)
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntryTest.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java?rev=1883723&r1=1883722&r2=1883723&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java Sun Nov 22 13:55:51 2020
@@ -18,11 +18,11 @@ package org.apache.pdfbox.pdfparser;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 import java.util.TreeSet;
 
 import org.apache.pdfbox.cos.COSArray;
@@ -32,7 +32,8 @@ import org.apache.pdfbox.cos.COSDocument
 import org.apache.pdfbox.cos.COSInteger;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdfwriter.COSWriterXRefEntry;
+import org.apache.pdfbox.pdfparser.xref.FreeXReference;
+import org.apache.pdfbox.pdfparser.xref.XReferenceEntry;
 
 /**
  * @author Alexander Funk
@@ -40,15 +41,9 @@ import org.apache.pdfbox.pdfwriter.COSWr
 public class PDFXRefStream
 {
 
-    private static final int ENTRY_OBJSTREAM = 2;
+    private final List<XReferenceEntry> streamData = new ArrayList<XReferenceEntry>();
 
-    private static final int ENTRY_NORMAL = 1;
-
-    private static final int ENTRY_FREE = 0;
-
-    private final Map<Long, Object> streamData;
-
-    private final Set<Long> objectNumbers;
+    private final Set<Long> objectNumbers = new TreeSet<>();;
 
     private final COSStream stream;
 
@@ -62,8 +57,6 @@ public class PDFXRefStream
     public PDFXRefStream(COSDocument cosDocument)
     {
         stream = cosDocument.createCOSStream();
-        streamData = new TreeMap<>();
-        objectNumbers = new TreeSet<>();
     }
 
     /**
@@ -144,26 +137,14 @@ public class PDFXRefStream
      * 
      * @param entry new entry to be added
      */
-    public void addEntry(COSWriterXRefEntry entry)
+    public void addEntry(XReferenceEntry entry)
     {
-        objectNumbers.add(entry.getKey().getNumber());
-        if (entry.isFree())
+        if (objectNumbers.contains(entry.getReferencedKey().getNumber()))
         {
-            // what would be a f-Entry in the xref table
-            FreeReference value = new FreeReference();
-            value.nextGenNumber = entry.getKey().getGeneration();
-            value.nextFree = entry.getKey().getNumber();
-            streamData.put(value.nextFree, value);
-        }
-        else
-        {
-            // we don't care for ObjectStreamReferences for now and only handle
-            // normal references that would be f-Entrys in the xref table.
-            NormalReference value = new NormalReference();
-            value.genNumber = entry.getKey().getGeneration();
-            value.offset = entry.getOffset();
-            streamData.put(entry.getKey().getNumber(), value);
+            return;
         }
+        objectNumbers.add(entry.getReferencedKey().getNumber());
+        streamData.add(entry);
     }
 
     /**
@@ -174,34 +155,11 @@ public class PDFXRefStream
     private int[] getWEntry()
     {
         long[] wMax = new long[3];
-        for ( Object entry : streamData.values() )
+        for (XReferenceEntry entry : streamData)
         {
-            if (entry instanceof FreeReference)
-            {
-                FreeReference free = (FreeReference)entry;
-                wMax[0] = Math.max(wMax[0], ENTRY_FREE); // the type field for a free reference
-                wMax[1] = Math.max(wMax[1], free.nextFree);
-                wMax[2] = Math.max(wMax[2], free.nextGenNumber);
-            }
-            else if (entry instanceof NormalReference)
-            {
-                NormalReference ref = (NormalReference)entry;
-                wMax[0] = Math.max(wMax[0], ENTRY_NORMAL); // the type field for a normal reference
-                wMax[1] = Math.max(wMax[1], ref.offset);
-                wMax[2] = Math.max(wMax[2], ref.genNumber);
-            }
-            else if (entry instanceof ObjectStreamReference)
-            {
-                ObjectStreamReference objStream = (ObjectStreamReference)entry;
-                wMax[0] = Math.max(wMax[0], ENTRY_OBJSTREAM); // the type field for a objstm reference
-                wMax[1] = Math.max(wMax[1], objStream.offset);
-                wMax[2] = Math.max(wMax[2], objStream.objectNumberOfObjectStream);
-            }
-            // TODO add here if new standard versions define new types
-            else
-            {
-                throw new RuntimeException("unexpected reference type");
-            }
+            wMax[0] = Math.max(wMax[0], entry.getFirstColumnValue());
+            wMax[1] = Math.max(wMax[1], entry.getSecondColumnValue());
+            wMax[2] = Math.max(wMax[2], entry.getThirdColumnValue());
         }
         // find the max bytes needed to display that column
         int[] w = new int[3];
@@ -277,70 +235,18 @@ public class PDFXRefStream
 
     private void writeStreamData(OutputStream os, int[] w) throws IOException
     {
-        // write dummy entry for object number 0
-        writeNumber(os, ENTRY_FREE, w[0]);
-        writeNumber(os, ENTRY_FREE, w[1]);
-        writeNumber(os, 0xFFFF, w[2]);
+        Collections.sort(streamData);
+        FreeXReference nullEntry = FreeXReference.NULL_ENTRY;
+        writeNumber(os, nullEntry.getFirstColumnValue(), w[0]);
+        writeNumber(os, nullEntry.getSecondColumnValue(), w[1]);
+        writeNumber(os, nullEntry.getThirdColumnValue(), w[2]);
         // iterate over all streamData and write it in the required format
-        for ( Object entry : streamData.values() )
+        for (XReferenceEntry entry : streamData)
         {
-            if (entry instanceof FreeReference)
-            {
-                FreeReference free = (FreeReference)entry;
-                writeNumber(os, ENTRY_FREE, w[0]);
-                writeNumber(os, free.nextFree, w[1]);
-                writeNumber(os, free.nextGenNumber, w[2]);
-            }
-            else if (entry instanceof NormalReference)
-            {
-                NormalReference ref = (NormalReference)entry;
-                writeNumber(os, ENTRY_NORMAL, w[0]);
-                writeNumber(os, ref.offset, w[1]);
-                writeNumber(os, ref.genNumber, w[2]);
-            }
-            else if (entry instanceof ObjectStreamReference)
-            {
-                ObjectStreamReference objStream = (ObjectStreamReference)entry;
-                writeNumber(os, ENTRY_OBJSTREAM, w[0]);
-                writeNumber(os, objStream.offset, w[1]);
-                writeNumber(os, objStream.objectNumberOfObjectStream, w[2]);
-            }
-            // TODO add here if new standard versions define new types
-            else
-            {
-                throw new RuntimeException("unexpected reference type");
-            }
+            writeNumber(os, entry.getFirstColumnValue(), w[0]);
+            writeNumber(os, entry.getSecondColumnValue(), w[1]);
+            writeNumber(os, entry.getThirdColumnValue(), w[2]);
         }
     }
 
-    /**
-     * A class representing an object stream reference. 
-     *
-     */
-    static class ObjectStreamReference
-    {
-        long objectNumberOfObjectStream;
-        long offset;
-    }
-
-    /**
-     * A class representing a normal reference. 
-     *
-     */
-    static class NormalReference
-    {
-        int genNumber;
-        long offset;
-    }
-
-    /**
-     * A class representing a free reference. 
-     *
-     */
-    static class FreeReference
-    {
-        int nextGenNumber;
-        long nextFree;
-    }
-
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * An extending class represents an entry, as it can be found in a PDF's crossreference stream ({@link PDFXRefStream}).
+ * Such an entry shall locate a PDF object/resource in a PDF document.
+ * 
+ * @author Christian Appl
+ */
+public abstract class AbstractXReference implements XReferenceEntry
+{
+
+    private final XReferenceType type;
+
+    /**
+     * Creates a crossreference stream entry of the given {@link XReferenceType}.
+     *
+     * @param type The {@link XReferenceType} of the crossreference stream entry.
+     */
+    public AbstractXReference(XReferenceType type)
+    {
+        this.type = type;
+    }
+
+    /**
+     * Returns the {@link XReferenceType} of this crossreference stream entry.
+     *
+     * @return The {@link XReferenceType} of this crossreference stream entry.
+     */
+    @Override
+    public XReferenceType getType()
+    {
+        return type;
+    }
+
+    /**
+     * Returns the value for the first column of the crossreference stream entry. (The numeric representation of this
+     * entry's (The numeric representation of this entry's {@link XReferenceType}.)
+     *
+     * @return The value for the first column of the crossreference stream entry.
+     */
+    @Override
+    public long getFirstColumnValue()
+    {
+        return getType().getNumericValue();
+    }
+
+    /**
+     * Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer
+     * as this object is less than, equal to, or greater than the specified object.
+     *
+     * @param xReferenceEntry the object to be compared.
+     * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
+     * the specified object.
+     */
+    @Override
+    public int compareTo(XReferenceEntry xReferenceEntry)
+    {
+        if (getReferencedKey() == null)
+        {
+            return -1;
+        }
+        else if (xReferenceEntry == null || xReferenceEntry.getReferencedKey() == null)
+        {
+            return 1;
+        }
+
+        return getReferencedKey().compareTo(xReferenceEntry.getReferencedKey());
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/AbstractXReference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.cos.COSObjectKey;
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * A class representing a free reference in a PDF's crossreference stream ({@link PDFXRefStream}).
+ * 
+ * @author Christian Appl
+ */
+public class FreeXReference extends AbstractXReference
+{
+
+    public static final FreeXReference NULL_ENTRY = new FreeXReference(new COSObjectKey(0, 65535));
+    private final COSObjectKey nextFreeKey;
+
+    /**
+     * Sets the given {@link COSObjectKey} as a free reference in a PDF's crossreference stream ({@link PDFXRefStream}).
+     *
+     * @param nextFreeKey The key, that shall be set as the free reference of the document.
+     */
+    public FreeXReference(COSObjectKey nextFreeKey)
+    {
+        super(XReferenceType.FREE);
+        this.nextFreeKey = nextFreeKey;
+    }
+
+    /**
+     * Returns the {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     */
+    @Override
+    public COSObjectKey getReferencedKey()
+    {
+        return nextFreeKey;
+    }
+
+    /**
+     * Returns the value for the second column of the crossreference stream entry. (This is the object number of the set
+     * next free {@link COSObjectKey} - for entries of this type.)
+     *
+     * @return The value for the second column of the crossreference stream entry.
+     */
+    @Override
+    public long getSecondColumnValue()
+    {
+        return getReferencedKey().getNumber();
+    }
+
+    /**
+     * Returns the value for the third column of the crossreference stream entry. (This is the generation number of the
+     * set next free {@link COSObjectKey} - for entries of this type.)
+     *
+     * @return The value for the third column of the crossreference stream entry.
+     */
+    @Override
+    public long getThirdColumnValue()
+    {
+        return getReferencedKey().getGeneration();
+    }
+
+    /**
+     * Returns a string representation of this crossreference stream entry.
+     *
+     * @return A string representation of this crossreference stream entry.
+     */
+    @Override
+    public String toString()
+    {
+        return "FreeReference{" + "nextFreeKey=" + nextFreeKey + ", type="
+                + getType().getNumericValue() + " }";
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/FreeXReference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.cos.*;
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * A class representing a normal reference in a PDF's crossreference stream ({@link PDFXRefStream}).
+ * 
+ * @author Christian Appl
+ */
+public class NormalXReference extends AbstractXReference
+{
+
+    private final long byteOffset;
+    private final COSObjectKey key;
+    private final COSBase object;
+    private final boolean objectStream;
+
+    /**
+     * Prepares a normal reference for the given {@link COSObject} in a PDF's crossreference stream
+     * ({@link PDFXRefStream}).
+     *
+     * @param byteOffset The byte offset of the {@link COSObject} in the PDF file.
+     * @param key The {@link COSObjectKey}, that is represented by this entry.
+     * @param object The {@link COSObject}, that is represented by this entry.
+     */
+    public NormalXReference(long byteOffset, COSObjectKey key, COSBase object)
+    {
+        super(XReferenceType.NORMAL);
+        this.byteOffset = byteOffset;
+        this.key = key;
+        this.object = object;
+        COSBase base = object;
+        if (base != null && (base instanceof COSStream || (base instanceof COSObject
+                && (base = ((COSObject) base).getObject()) instanceof COSStream)))
+        {
+            this.objectStream = COSName.OBJ_STM.equals(((COSStream) base).getCOSName(COSName.TYPE));
+        }
+        else
+        {
+            this.objectStream = false;
+        }
+    }
+
+    /**
+     * Returns the byte offset of the {@link COSObject} in the PDF file.
+     *
+     * @return The byte offset of the {@link COSObject} in the PDF file.
+     */
+    public long getByteOffset()
+    {
+        return byteOffset;
+    }
+
+    /**
+     * Returns the {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     */
+    @Override
+    public COSObjectKey getReferencedKey()
+    {
+        return key;
+    }
+
+    /**
+     * Returns the {@link COSObject}, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObject}, that is described by this crossreference stream entry.
+     */
+    public COSBase getObject()
+    {
+        return object;
+    }
+
+    /**
+     * Returns true, if the referenced object is an object stream.
+     *
+     * @return True, if the referenced object is an object stream.
+     */
+    public boolean isObjectStream()
+    {
+        return objectStream;
+    }
+
+    /**
+     * Returns the value for the second column of the crossreference stream entry. (This is byte offset of the
+     * {@link COSObject} in the PDF file - for entries of this type.)
+     *
+     * @return The value for the second column of the crossreference stream entry.
+     */
+    @Override
+    public long getSecondColumnValue()
+    {
+        return getByteOffset();
+    }
+
+    /**
+     * Returns the value for the third column of the crossreference stream entry. (This is the generation number of the
+     * set {@link COSObjectKey} - for entries of this type.)
+     *
+     * @return The value for the third column of the crossreference stream entry.
+     */
+    @Override
+    public long getThirdColumnValue()
+    {
+        return getReferencedKey().getGeneration();
+    }
+
+    /**
+     * Returns a string representation of this crossreference stream entry.
+     *
+     * @return A string representation of this crossreference stream entry.
+     */
+    @Override
+    public String toString()
+    {
+        return (isObjectStream() ? "ObjectStreamParent{" : "NormalReference{") + " key=" + key
+                + ", type=" + getType().getNumericValue() + ", byteOffset=" + byteOffset + " }";
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/NormalXReference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSObject;
+import org.apache.pdfbox.cos.COSObjectKey;
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * A class representing a reference to an object stream entry in a PDF's crossreference stream ({@link PDFXRefStream}).
+ * 
+ * @author Christian Appl
+ */
+public class ObjectStreamXReference extends AbstractXReference
+{
+
+    private final int objectStreamIndex;
+    private final COSObjectKey key;
+    private final COSBase object;
+    private final COSObjectKey parentKey;
+
+    /**
+     * Prepares a object stream entry reference for the given {@link COSObject} in a PDF's crossreference stream
+     * ({@link PDFXRefStream}).
+     *
+     * @param objectStreamIndex The index of the {@link COSObject} in the containing object stream.
+     * @param key The {@link COSObjectKey}, that is represented by this entry.
+     * @param object The {@link COSObject}, that is represented by this entry.
+     * @param parentKey The {@link COSObjectKey} of the object stream, that is containing the object.
+     */
+    public ObjectStreamXReference(int objectStreamIndex, COSObjectKey key, COSBase object,
+            COSObjectKey parentKey)
+    {
+        super(XReferenceType.OBJECT_STREAM_ENTRY);
+        this.objectStreamIndex = objectStreamIndex;
+        this.key = key;
+        this.object = object;
+        this.parentKey = parentKey;
+    }
+
+    /**
+     * Returns the index of the {@link COSObject} in it's containing object stream.
+     *
+     * @return The index of the {@link COSObject} in it's containing object stream.
+     */
+    public int getObjectStreamIndex()
+    {
+        return objectStreamIndex;
+    }
+
+    /**
+     * Returns the {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     */
+    @Override
+    public COSObjectKey getReferencedKey()
+    {
+        return key;
+    }
+
+    /**
+     * Returns the {@link COSObject}, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObject}, that is described by this crossreference stream entry.
+     */
+    public COSBase getObject()
+    {
+        return object;
+    }
+
+    /**
+     * Returns the {@link COSObjectKey} of the object stream, that is containing the object.
+     *
+     * @return The {@link COSObjectKey} of the object stream, that is containing the object.
+     */
+    public COSObjectKey getParentKey()
+    {
+        return parentKey;
+    }
+
+    /**
+     * Returns the value for the second column of the crossreference stream entry. (This is object number from the
+     * {@link COSObjectKey} of the object stream, that is containing the object represented by this entry - for entries
+     * of this type..)
+     *
+     * @return The value for the second column of the crossreference stream entry.
+     */
+    @Override
+    public long getSecondColumnValue()
+    {
+        return getParentKey().getNumber();
+    }
+
+    /**
+     * Returns the value for the third column of the crossreference stream entry. (This is index of the
+     * {@link COSObject} in the containing object stream - for entries of this type.)
+     *
+     * @return The value for the third column of the crossreference stream entry.
+     */
+    @Override
+    public long getThirdColumnValue()
+    {
+        return getObjectStreamIndex();
+    }
+
+    /**
+     * Returns a string representation of this crossreference stream entry.
+     *
+     * @return A string representation of this crossreference stream entry.
+     */
+    @Override
+    public String toString()
+    {
+        return "ObjectStreamEntry{" + " key=" + key + ", type=" + getType().getNumericValue()
+                + ", objectStreamIndex=" + objectStreamIndex + ", parent=" + parentKey + " }";
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/ObjectStreamXReference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.cos.COSObjectKey;
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * An implementing class represents an entry, as it can be found in a PDF's crossreference stream
+ * ({@link PDFXRefStream}). Such an entry shall locate a PDF object/resource in a PDF document.
+ * 
+ * @author Christian Appl
+ */
+public interface XReferenceEntry extends Comparable<XReferenceEntry>
+{
+
+    /**
+     * Returns the {@link XReferenceType} of this crossreference stream entry.
+     *
+     * @return The {@link XReferenceType} of this crossreference stream entry.
+     */
+    XReferenceType getType();
+
+    /**
+     * Returns the {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     *
+     * @return The {@link COSObjectKey} of the object, that is described by this crossreference stream entry.
+     */
+    COSObjectKey getReferencedKey();
+
+    /**
+     * Returns the value for the first column of the crossreference stream entry. (The numeric representation of this
+     * entry's {@link XReferenceType}.)
+     *
+     * @return The value for the first column of the crossreference stream entry.
+     */
+    long getFirstColumnValue();
+
+    /**
+     * Returns the value for the second column of the crossreference stream entry. (It's meaning depends on the
+     * {@link XReferenceType} of this entry.)
+     *
+     * @return The value for the second column of the crossreference stream entry.
+     */
+    long getSecondColumnValue();
+
+    /**
+     * Returns the value for the third column of the crossreference stream entry. (It's meaning depends on the
+     * {@link XReferenceType} of this entry.)
+     *
+     * @return The value for the third column of the crossreference stream entry.
+     */
+    long getThirdColumnValue();
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java?rev=1883723&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java Sun Nov 22 13:55:51 2020
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdfparser.xref;
+
+import org.apache.pdfbox.pdfparser.PDFXRefStream;
+
+/**
+ * An instance of this class represents a type for a {@link XReferenceEntry}, as it can be found in a PDF's
+ * {@link PDFXRefStream}.
+ * 
+ * @author Christian Appl
+ */
+public enum XReferenceType
+{
+
+    FREE(0), NORMAL(1), OBJECT_STREAM_ENTRY(2);
+
+    private final int numericValue;
+
+    /**
+     * Represents a type for a {@link XReferenceEntry}, as it can be found in a PDF's {@link PDFXRefStream}.
+     *
+     * @param numericValue The numeric representation of this type.
+     */
+    XReferenceType(int numericValue)
+    {
+        this.numericValue = numericValue;
+    }
+
+    /**
+     * Returns the numeric representation of this type.
+     *
+     * @return The numeric representation of this type.
+     */
+    public int getNumericValue()
+    {
+        return numericValue;
+    }
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/xref/XReferenceType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java?rev=1883723&r1=1883722&r2=1883723&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java Sun Nov 22 13:55:51 2020
@@ -61,6 +61,9 @@ import org.apache.pdfbox.io.IOUtils;
 import org.apache.pdfbox.io.RandomAccessInputStream;
 import org.apache.pdfbox.io.RandomAccessRead;
 import org.apache.pdfbox.pdfparser.PDFXRefStream;
+import org.apache.pdfbox.pdfparser.xref.FreeXReference;
+import org.apache.pdfbox.pdfparser.xref.NormalXReference;
+import org.apache.pdfbox.pdfparser.xref.XReferenceEntry;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.encryption.ProtectionPolicy;
 import org.apache.pdfbox.pdmodel.encryption.SecurityHandler;
@@ -186,7 +189,7 @@ public class COSWriter implements ICOSVi
     private final Map<COSObjectKey,COSBase> keyObject = new HashMap<>();
 
     // the list of x ref entries to be made so far
-    private final List<COSWriterXRefEntry> xRefEntries = new ArrayList<>();
+    private final List<XReferenceEntry> xRefEntries = new ArrayList<>();
     private final Set<COSBase> objectsToWriteSet = new HashSet<>();
 
     //A list of objects to write.
@@ -328,7 +331,7 @@ public class COSWriter implements ICOSVi
      *
      * @param entry The new entry to add.
      */
-    protected void addXRefEntry(COSWriterXRefEntry entry)
+    protected void addXRefEntry(XReferenceEntry entry)
     {
         getXRefEntries().add(entry);
     }
@@ -405,7 +408,7 @@ public class COSWriter implements ICOSVi
      *
      * @return All available xref entries.
      */
-    protected List<COSWriterXRefEntry> getXRefEntries()
+    protected List<XReferenceEntry> getXRefEntries()
     {
         return xRefEntries;
     }
@@ -555,7 +558,7 @@ public class COSWriter implements ICOSVi
             // find the physical reference
             currentObjectKey = getObjectKey( obj );
             // add a x ref entry
-            addXRefEntry( new COSWriterXRefEntry(getStandardOutput().getPos(), obj, currentObjectKey));
+            addXRefEntry(new NormalXReference(getStandardOutput().getPos(), currentObjectKey, obj));
             // write the object
             getStandardOutput().write(String.valueOf(currentObjectKey.getNumber()).getBytes(StandardCharsets.ISO_8859_1));
             getStandardOutput().write(SPACE);
@@ -616,8 +619,8 @@ public class COSWriter implements ICOSVi
         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);
+        XReferenceEntry lastEntry = getXRefEntries().get(getXRefEntries().size() - 1);
+        trailer.setLong(COSName.SIZE, lastEntry.getReferencedKey().getNumber() + 1);
         // Only need to stay, if an incremental update will be performed
         if (!incrementalUpdate) 
         {
@@ -691,7 +694,7 @@ public class COSWriter implements ICOSVi
     // writes the "xref" table
     private void doWriteXRefTable() throws IOException
     {
-        addXRefEntry(COSWriterXRefEntry.getNullEntry());
+        addXRefEntry(FreeXReference.NULL_ENTRY);
 
         // sort xref, needed only if object keys not regenerated
         Collections.sort(getXRefEntries());
@@ -863,15 +866,15 @@ public class COSWriter implements ICOSVi
         getStandardOutput().writeEOL();
     }
 
-    private void writeXrefEntry(COSWriterXRefEntry entry) throws IOException
+    private void writeXrefEntry(XReferenceEntry entry) throws IOException
     {
-        String offset = formatXrefOffset.format(entry.getOffset());
-        String generation = formatXrefGeneration.format(entry.getKey().getGeneration());
+        String offset = formatXrefOffset.format(entry.getSecondColumnValue());
+        String generation = formatXrefGeneration.format(entry.getThirdColumnValue());
         getStandardOutput().write(offset.getBytes(StandardCharsets.ISO_8859_1));
         getStandardOutput().write(SPACE);
         getStandardOutput().write(generation.getBytes(StandardCharsets.ISO_8859_1));
         getStandardOutput().write(SPACE);
-        getStandardOutput().write(entry.isFree() ? XREF_FREE : XREF_USED);
+        getStandardOutput().write(entry instanceof FreeXReference ? XREF_FREE : XREF_USED);
         getStandardOutput().writeCRLF();
     }
 
@@ -893,15 +896,15 @@ public class COSWriter implements ICOSVi
      * @param xRefEntriesList list with the xRef entries that was written
      * @return a integer array with the ranges
      */
-    protected Long[] getXRefRanges(List<COSWriterXRefEntry> xRefEntriesList)
+    protected Long[] getXRefRanges(List<XReferenceEntry> xRefEntriesList)
     {
         long last = -2;
         long count = 1;
 
         List<Long> list = new ArrayList<>();
-        for (COSWriterXRefEntry object : xRefEntriesList)
+        for (XReferenceEntry entry : xRefEntriesList)
         {
-            long nr = object.getKey().getNumber();
+            long nr = entry.getReferencedKey().getNumber();
             if (nr == last + 1)
             {
                 ++count;
@@ -920,12 +923,12 @@ public class COSWriter implements ICOSVi
             }
         }
         // If no new entry is found, we need to write out the last result
-        if(xRefEntriesList.size() > 0)
+        if (xRefEntriesList.size() > 0)
         {
             list.add(last - count + 1);
             list.add(count);
         }
-        return list.toArray(new Long[list.size()]);
+        return list.toArray(new Long[0]);
     }
     
     /**