You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ms...@apache.org on 2021/10/03 13:24:54 UTC
svn commit: r1893854 - in /pdfbox/trunk/pdfbox/src:
main/java/org/apache/pdfbox/cos/ main/java/org/apache/pdfbox/cos/observer/
main/java/org/apache/pdfbox/pdfwriter/ main/java/org/apache/pdfbox/pdmodel/
main/java/org/apache/pdfbox/pdmodel/fdf/ test/jav...
Author: msahyoun
Date: Sun Oct 3 13:24:54 2021
New Revision: 1893854
URL: http://svn.apache.org/viewvc?rev=1893854&view=rev
Log:
PDFBOX-5263: introduce state based incremental handling as suggested by Christian Appl
Added:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocumentState.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSIncrement.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateState.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSIncrement.java
- copied, changed from r1893853, pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java
Removed:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfoObserver.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/observer/
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObject.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfo.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDocument.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfo.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java Sun Oct 3 13:24:54 2021
@@ -24,9 +24,6 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
-import org.apache.pdfbox.cos.observer.event.COSAddEvent;
-import org.apache.pdfbox.cos.observer.event.COSReplaceEvent;
-import org.apache.pdfbox.cos.observer.event.COSRemoveEvent;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
/**
@@ -37,13 +34,14 @@ import org.apache.pdfbox.pdmodel.common.
public class COSArray extends COSBase implements Iterable<COSBase>, COSUpdateInfo
{
private final List<COSBase> objects = new ArrayList<>();
+ private final COSUpdateState updateState;
/**
* Constructor.
*/
public COSArray()
{
- //default constructor
+ updateState = new COSUpdateState(this);
}
/**
@@ -57,9 +55,9 @@ public class COSArray extends COSBase im
{
throw new IllegalArgumentException("List of COSObjectables cannot be null");
}
+ updateState = new COSUpdateState(this);
cosObjectables.forEach(cosObjectable ->
objects.add(cosObjectable != null ? cosObjectable.getCOSObject() : null));
- reportUpdate(new COSAddEvent<>(this, objects));
}
/**
@@ -70,7 +68,7 @@ public class COSArray extends COSBase im
public void add( COSBase object )
{
objects.add( object );
- reportUpdate(new COSAddEvent<>(this, object));
+ getUpdateState().update(object);
}
/**
@@ -81,7 +79,7 @@ public class COSArray extends COSBase im
public void add( COSObjectable object )
{
objects.add( object.getCOSObject() );
- reportUpdate(new COSAddEvent<>(this, object.getCOSObject()));
+ getUpdateState().update(object.getCOSObject());
}
/**
@@ -94,7 +92,7 @@ public class COSArray extends COSBase im
public void add( int i, COSBase object)
{
objects.add( i, object );
- reportUpdate(new COSAddEvent<>(this, object));
+ getUpdateState().update(object);
}
/**
@@ -102,9 +100,8 @@ public class COSArray extends COSBase im
*/
public void clear()
{
- List<COSBase> removed = new ArrayList<>(objects);
objects.clear();
- reportUpdate(new COSRemoveEvent<>(this, removed));
+ getUpdateState().update();
}
/**
@@ -115,7 +112,7 @@ public class COSArray extends COSBase im
public void removeAll( Collection<COSBase> objectsList )
{
objects.removeAll( objectsList );
- reportUpdate(new COSRemoveEvent<>(this, objectsList));
+ getUpdateState().update();
}
/**
@@ -125,10 +122,8 @@ public class COSArray extends COSBase im
*/
public void retainAll( Collection<COSBase> objectsList )
{
- List<COSBase> removed = new ArrayList<>(this.objects);
- removed.removeAll(objectsList);
objects.retainAll( objectsList );
- reportUpdate(new COSRemoveEvent<>(this, removed));
+ getUpdateState().update();
}
/**
@@ -139,7 +134,7 @@ public class COSArray extends COSBase im
public void addAll( Collection<COSBase> objectsList )
{
objects.addAll( objectsList );
- reportUpdate(new COSAddEvent<>(this, objectsList));
+ getUpdateState().update(objectsList);
}
/**
@@ -152,7 +147,7 @@ public class COSArray extends COSBase im
if( objectList != null )
{
objects.addAll( objectList.objects );
- reportUpdate(new COSAddEvent<>(this, objectList));
+ getUpdateState().update(objectList);
}
}
@@ -166,7 +161,7 @@ public class COSArray extends COSBase im
public void addAll( int i, Collection<COSBase> objectList )
{
objects.addAll( i, objectList );
- reportUpdate(new COSAddEvent<>(this, objectList));
+ getUpdateState().update(objectList);
}
/**
@@ -177,13 +172,8 @@ public class COSArray extends COSBase im
*/
public void set( int index, COSBase object )
{
- COSBase replacedEntry = null;
- if(index >= 0 && index < size())
- {
- replacedEntry = get(index);
- }
objects.set( index, object );
- reportUpdate(new COSReplaceEvent<>(this, replacedEntry, object));
+ getUpdateState().update(object);
}
/**
@@ -194,14 +184,8 @@ public class COSArray extends COSBase im
*/
public void set( int index, int intVal )
{
- COSBase replacedEntry = null;
- if(index >= 0 && index < size())
- {
- replacedEntry = get(index);
- }
- COSBase replacingEntry = COSInteger.get(intVal);
- objects.set( index, replacingEntry );
- reportUpdate(new COSReplaceEvent<>(this, replacedEntry, replacingEntry));
+ objects.set( index, COSInteger.get(intVal));
+ getUpdateState().update();
}
/**
@@ -212,18 +196,13 @@ public class COSArray extends COSBase im
*/
public void set( int index, COSObjectable object )
{
- COSBase replacedEntry = null;
- if(index >= 0 && index < size())
- {
- replacedEntry = get(index);
- }
COSBase base = null;
if( object != null )
{
base = object.getCOSObject();
}
objects.set( index, base );
- reportUpdate(new COSReplaceEvent<>(this, replacedEntry, base));
+ getUpdateState().update(base);
}
/**
@@ -414,7 +393,7 @@ public class COSArray extends COSBase im
public COSBase remove( int i )
{
COSBase removedEntry = objects.remove( i );
- reportUpdate(new COSRemoveEvent<>(this, removedEntry));
+ getUpdateState().update();
return removedEntry;
}
@@ -429,7 +408,7 @@ public class COSArray extends COSBase im
public boolean remove( COSBase o )
{
boolean removed = objects.remove( o );
- reportUpdate(new COSRemoveEvent<>(this, o));
+ getUpdateState().update();
return removed;
}
@@ -558,13 +537,12 @@ public class COSArray extends COSBase im
*/
public void growToSize( int size, COSBase object )
{
- List<COSBase> addedObjects = new ArrayList<>();
while( size() < size )
{
add( object );
- addedObjects.add(object);
+ getUpdateState().update(object);
}
- reportUpdate(new COSAddEvent<>(this, addedObjects));
+ getUpdateState().update();
}
/**
@@ -732,5 +710,17 @@ public class COSArray extends COSBase im
strings.forEach(s -> retval.add(new COSString(s)));
return retval;
}
-
+
+ /**
+ * Returns the current {@link COSUpdateState} of this {@link COSArray}.
+ *
+ * @return The current {@link COSUpdateState} of this {@link COSArray}.
+ * @see COSUpdateState
+ */
+ @Override
+ public COSUpdateState getUpdateState()
+ {
+ return updateState;
+ }
+
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java Sun Oct 3 13:24:54 2021
@@ -16,14 +16,9 @@
*/
package org.apache.pdfbox.cos;
-import org.apache.pdfbox.cos.observer.event.COSDirectObjectEvent;
-import org.apache.pdfbox.cos.observer.event.COSEvent;
-import org.apache.pdfbox.cos.observer.COSObserver;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* The base object that all objects in the PDF document will extend.
@@ -32,8 +27,7 @@ import java.util.concurrent.CopyOnWriteA
*/
public abstract class COSBase implements COSObjectable
{
-
- private final List<COSObserver> cosChangeObservers = new CopyOnWriteArrayList<>();
+
private boolean direct;
private COSObjectKey key;
@@ -83,9 +77,6 @@ public abstract class COSBase implements
public void setDirect(boolean direct)
{
this.direct = direct;
- if(direct){
- reportUpdate(new COSDirectObjectEvent<>(this));
- }
}
/**
@@ -108,50 +99,4 @@ public abstract class COSBase implements
this.key = key;
}
- /**
- * Register the given {@link COSObserver} to this {@link COSBase}.
- *
- * @param observer The {@link COSObserver} to register.
- * @see #reportUpdate(COSEvent)
- */
- public void registerObserver(COSObserver observer)
- {
- this.cosChangeObservers.add(observer);
- }
-
- /**
- * Unregister the given {@link COSObserver} from this {@link COSBase}.
- *
- * @param observer The {@link COSObserver} to unregister.
- * @see #reportUpdate(COSEvent)
- */
- public void unregisterObserver(COSObserver observer)
- {
- this.cosChangeObservers.remove(observer);
- }
-
- /**
- * Returns the {@link COSObserver}s registered to this {@link COSBase}.
- *
- * @return A list of all {@link COSObserver}s currently registered to this {@link COSBase}.
- */
- public List<COSObserver> getRegisteredObservers()
- {
- return this.cosChangeObservers;
- }
-
- /**
- * Report a change to this {@link COSBase} as a {@link COSEvent} to all registered {@link COSObserver}s.
- *
- * @param event The {@link COSEvent} to report.
- * @param <COS_TYPE> The explicit {@link COSBase} type of the reporting object.
- * @see #registerObserver(COSObserver)
- */
- public <COS_TYPE extends COSBase> void reportUpdate(COSEvent<COS_TYPE> event)
- {
- for (COSObserver observer : this.cosChangeObservers) {
- observer.reportUpdate(event);
- }
- }
-
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java Sun Oct 3 13:24:54 2021
@@ -30,9 +30,6 @@ import java.util.function.BiConsumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.observer.event.COSAddEvent;
-import org.apache.pdfbox.cos.observer.event.COSReplaceEvent;
-import org.apache.pdfbox.cos.observer.event.COSRemoveEvent;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.util.DateConverter;
@@ -58,13 +55,14 @@ public class COSDictionary extends COSBa
* The name-value pairs of this dictionary. The pairs are kept in the order they were added to the dictionary.
*/
protected Map<COSName, COSBase> items = new SmallMap<>();
+ private final COSUpdateState updateState;
/**
* Constructor.
*/
public COSDictionary()
{
- // default constructor
+ updateState = new COSUpdateState(this);
}
/**
@@ -74,8 +72,8 @@ public class COSDictionary extends COSBa
*/
public COSDictionary(COSDictionary dict)
{
+ updateState = new COSUpdateState(this);
items.putAll(dict.items);
- reportUpdate(new COSAddEvent<>(this, items.values()));
}
/**
@@ -131,9 +129,8 @@ public class COSDictionary extends COSBa
*/
public void clear()
{
- List<COSBase> removed = new ArrayList<>(items.values());
items.clear();
- reportUpdate(new COSRemoveEvent<>(this, removed));
+ getUpdateState().update();
}
/**
@@ -206,20 +203,8 @@ public class COSDictionary extends COSBa
}
else
{
- COSBase replacedEntry = null;
- if (items.containsKey(key))
- {
- replacedEntry = items.get(key);
- }
items.put(key, value);
- if(replacedEntry != null)
- {
- reportUpdate(new COSReplaceEvent<>(this, replacedEntry, value));
- }
- else
- {
- reportUpdate(new COSAddEvent<>(this, value));
- }
+ getUpdateState().update(value);
}
}
@@ -1168,9 +1153,8 @@ public class COSDictionary extends COSBa
*/
public void removeItem(COSName key)
{
- COSBase removed = getItem(key);
items.remove(key);
- reportUpdate(new COSRemoveEvent<>(this, removed));
+ getUpdateState().update();
}
/**
@@ -1416,4 +1400,17 @@ public class COSDictionary extends COSBa
}
return base.toString();
}
+
+ /**
+ * Returns the current {@link COSUpdateState} of this {@link COSDictionary}.
+ *
+ * @return The current {@link COSUpdateState} of this {@link COSDictionary}.
+ * @see COSUpdateState
+ */
+ @Override
+ public COSUpdateState getUpdateState()
+ {
+ return updateState;
+ }
+
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java Sun Oct 3 13:24:54 2021
@@ -46,8 +46,7 @@ public class COSDocument extends COSBase
* Log instance.
*/
private static final Log LOG = LogFactory.getLog(COSDocument.class);
-
- private final COSUpdateInfoObserver updateObserver;
+
private float version = 1.4f;
/**
@@ -64,7 +63,7 @@ public class COSDocument extends COSBase
new HashMap<>();
/**
- * List containing all streams which are created when creating a new pdf.
+ * List containing all streams which are created when creating a new pdf.
*/
private final List<COSStream> streams = new ArrayList<>();
@@ -73,8 +72,8 @@ public class COSDocument extends COSBase
*/
private COSDictionary trailer;
- /**
- * Signal that document is already decrypted.
+ /**
+ * Signal that document is already decrypted.
*/
private boolean isDecrypted = false;
@@ -92,6 +91,8 @@ public class COSDocument extends COSBase
private long highestXRefObjectNumber;
private final ICOSParser parser;
+
+ private final COSDocumentState documentState = new COSDocumentState();
/**
* Constructor. Uses main memory to buffer PDF streams.
@@ -131,7 +132,6 @@ public class COSDocument extends COSBase
*/
public COSDocument(MemoryUsageSetting memUsageSetting, ICOSParser parser)
{
- this.updateObserver = new COSUpdateInfoObserver(this);
try
{
if (memUsageSetting != null)
@@ -365,7 +365,7 @@ public class COSDocument extends COSBase
public void setTrailer(COSDictionary newTrailer)
{
trailer = newTrailer;
- updateObserver.monitor(newTrailer);
+ trailer.getUpdateState().setOriginDocumentState(documentState);
}
/**
@@ -542,15 +542,16 @@ public class COSDocument extends COSBase
{
isXRefStream = isXRefStreamValue;
}
-
+
/**
- * Returns the {@link COSUpdateInfoObserver}, that is keeping track of changes to this {@link COSDocument}.
+ * Returns the {@link COSDocumentState} of this {@link COSDocument}.
*
- * @return The {@link COSUpdateInfoObserver}, that is keeping track of changes to this {@link COSDocument}.
+ * @return The {@link COSDocumentState} of this {@link COSDocument}.
+ * @see COSDocumentState
*/
- public COSUpdateInfoObserver getUpdateObserver()
+ public COSDocumentState getDocumentState()
{
- return updateObserver;
+ return documentState;
}
-
+
}
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocumentState.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocumentState.java?rev=1893854&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocumentState.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocumentState.java Sun Oct 3 13:24:54 2021
@@ -0,0 +1,58 @@
+/*
+ * 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.cos;
+
+/**
+ * An instance of {@link COSDocumentState} collects all known states a {@link COSDocument} may have and shall allow
+ * their evaluation.
+ *
+ * @author Christian Appl
+ * @see COSDocument
+ */
+public class COSDocumentState
+{
+
+ /**
+ * The parsing state of the document.
+ * <ul>
+ * <li>{@code true}, if the document is currently being parsed. (initial state)</li>
+ * <li>{@code false}, if the document's parsing completed and it may be edited and updated.</li>
+ * </ul>
+ */
+ private boolean parsing = true;
+
+ /**
+ * Sets the {@link #parsing} state of the document.
+ *
+ * @param parsing The {@link #parsing} state to set.
+ */
+ public void setParsing(boolean parsing)
+ {
+ this.parsing = parsing;
+ }
+
+ /**
+ * Returns {@code true}, if the document´s {@link #parsing} is completed and it may be updated.
+ *
+ * @return {@code true}, if the document´s {@link #parsing} is completed and it may be updated.
+ */
+ public boolean isAcceptingUpdates()
+ {
+ return !parsing;
+ }
+
+}
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSIncrement.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSIncrement.java?rev=1893854&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSIncrement.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSIncrement.java Sun Oct 3 13:24:54 2021
@@ -0,0 +1,358 @@
+/*
+ * 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.cos;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * A {@link COSIncrement} starts at a given {@link COSUpdateInfo} to collect updates, that have been made to a
+ * {@link COSDocument} and therefore should be added to it´s next increment.
+ *
+ * @author Christian Appl
+ * @see COSUpdateState
+ * @see COSUpdateInfo
+ */
+public class COSIncrement implements Iterable<COSBase>
+{
+
+ /**
+ * Contains the {@link COSBase}s, that shall be added to the increment at top level.
+ */
+ private final Set<COSBase> objects = new LinkedHashSet<>();
+ /**
+ * Contains the direct {@link COSBase}s, that are either contained written directly by structures contained in
+ * {@link #objects} or that must be excluded from being written as indirect {@link COSObject}s for other reasons.
+ */
+ private final Set<COSBase> excluded = new HashSet<>();
+ /**
+ * Contains all {@link COSObject}s, that have already been processed by this {@link COSIncrement} and shall not be
+ * processed again.
+ */
+ private final Set<COSObject> processedObjects = new HashSet<>();
+ /**
+ * Contains the {@link COSUpdateInfo} that this {@link COSIncrement} creates an increment for.
+ */
+ private final COSUpdateInfo incrementOrigin;
+ /**
+ * Whether this {@link COSIncrement} has already been determined, or must still be evaluated.
+ */
+ private boolean initialized = false;
+
+ /**
+ * Creates a new {@link COSIncrement} for the given {@link COSUpdateInfo}, the increment will use it´s
+ * {@link COSDocumentState} as it´s own origin and shall conllect all updates contained in the given
+ * {@link COSUpdateInfo}.<br>
+ * Should the given object be {@code null}, the resulting increment shall be empty.
+ *
+ * @param incrementOrigin The {@link COSUpdateInfo} serving as an update source for this {@link COSIncrement}.
+ */
+ public COSIncrement(COSUpdateInfo incrementOrigin)
+ {
+ this.incrementOrigin = incrementOrigin;
+ }
+
+ /**
+ * Collect all updates made to the given {@link COSBase} and it's contained structures.<br>
+ * This shall forward all {@link COSUpdateInfo} objects to the proper specialized collection methods.
+ *
+ * @param base The {@link COSBase} updates shall be collected for.
+ * @return Returns {@code true}, if the {@link COSBase} represents a direct child structure, that would require it´s
+ * parent to be updated instead.
+ * @see #collect(COSDictionary)
+ * @see #collect(COSArray)
+ * @see #collect(COSObject)
+ */
+ private boolean collect(COSBase base)
+ {
+ if(contains(base))
+ {
+ return false;
+ }
+ // handle updatable objects:
+ if(base instanceof COSDictionary)
+ {
+ return collect((COSDictionary) base);
+ }
+ else if(base instanceof COSObject)
+ {
+ return collect((COSObject) base);
+ }
+ else if(base instanceof COSArray)
+ {
+ return collect((COSArray) base);
+ }
+ return false;
+ }
+
+ /**
+ * Collect all updates made to the given {@link COSDictionary} and it's contained structures.
+ *
+ * @param dictionary The {@link COSDictionary} updates shall be collected for.
+ * @return Returns {@code true}, if the {@link COSDictionary} represents a direct child structure, that would
+ * require it´s parent to be updated instead.
+ */
+ private boolean collect(COSDictionary dictionary)
+ {
+ COSUpdateState updateState = dictionary.getUpdateState();
+ // Is definitely part of the increment?
+ if(!isExcluded(dictionary) && !contains(dictionary) && updateState.isUpdated())
+ {
+ add(dictionary);
+ }
+ boolean childDemandsParentUpdate = false;
+ // Collect children:
+ for(COSBase entry : dictionary.getValues())
+ {
+ // Primitives can not be part of an increment. (on top level)
+ if(!(entry instanceof COSUpdateInfo) || contains(entry))
+ {
+ continue;
+ }
+ COSUpdateInfo updatableEntry = (COSUpdateInfo) entry;
+ COSUpdateState entryUpdateState = ((COSUpdateInfo) entry).getUpdateState();
+ // Entries with different document origin must be part of the increment!
+ updateDifferentOrigin(entryUpdateState);
+ // Always attempt to write COSArrays as direct objects.
+ if(updatableEntry.isNeedToBeUpdated() &&
+ ((!(entry instanceof COSObject) && entry.isDirect()) || entry instanceof COSArray))
+ {
+ // Exclude direct entries from the increment!
+ exclude(entry);
+ childDemandsParentUpdate = true;
+ }
+ // Collect descendants:
+ childDemandsParentUpdate = collect(entry) || childDemandsParentUpdate;
+ }
+
+ if(isExcluded(dictionary))
+ {
+ return childDemandsParentUpdate;
+ }
+ else
+ {
+ if(childDemandsParentUpdate && !contains(dictionary))
+ {
+ add(dictionary);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Collect all updates made to the given {@link COSArray} and it's contained structures.
+ *
+ * @param array The {@link COSDictionary} updates shall be collected for.
+ * @return Returns {@code true}, if the {@link COSArray}´s elements changed. A {@link COSArray} shall always be
+ * treated as a direct structure, that would require it´s parent to be updated instead.
+ */
+ private boolean collect(COSArray array)
+ {
+ COSUpdateState updateState = array.getUpdateState();
+ boolean childDemandsParentUpdate = updateState.isUpdated();
+ for(COSBase entry : array)
+ {
+ // Primitives can not be part of an increment. (on top level)
+ if(!(entry instanceof COSUpdateInfo) || contains(entry))
+ {
+ continue;
+ }
+ COSUpdateState entryUpdateState = ((COSUpdateInfo) entry).getUpdateState();
+ // Entries with different document origin must be part of the increment!
+ updateDifferentOrigin(entryUpdateState);
+ // Collect descendants:
+ childDemandsParentUpdate = collect(entry) || childDemandsParentUpdate;
+ }
+ return childDemandsParentUpdate;
+ }
+
+ /**
+ * Collect all updates made to the given {@link COSObject} and it's contained structures.
+ *
+ * @param object The {@link COSObject} updates shall be collected for.
+ * @return Always returns {@code false}. {@link COSObject}s by definition are indirect and shall never cause a
+ * parent structure to be updated.
+ */
+ private boolean collect(COSObject object)
+ {
+ if(contains(object))
+ {
+ return false;
+ }
+ addProcessedObject(object);
+ COSUpdateState updateState = object.getUpdateState();
+ // Objects with different document origin must be part of the increment!
+ updateDifferentOrigin(updateState);
+ // determine actual, if necessary or possible without dereferencing:
+ COSUpdateInfo actual = null;
+ if(updateState.isUpdated() || object.isDereferenced())
+ {
+ COSBase base = object.getObject();
+ if(base instanceof COSUpdateInfo)
+ {
+ actual = (COSUpdateInfo) base;
+ }
+ }
+ // Skip?
+ if(actual == null || contains(actual.getCOSObject()))
+ {
+ return false;
+ }
+ boolean childDemandsParentUpdate = false;
+ COSUpdateState actualUpdateState = actual.getUpdateState();
+ if(actualUpdateState.isUpdated())
+ {
+ childDemandsParentUpdate = true;
+ }
+ exclude(actual.getCOSObject());
+ childDemandsParentUpdate = collect(actual.getCOSObject()) || childDemandsParentUpdate;
+ if(updateState.isUpdated() || childDemandsParentUpdate)
+ {
+ add(actual.getCOSObject());
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true}, if the given {@link COSBase} is already known to and has been processed by this
+ * {@link COSIncrement}.
+ *
+ * @param base The {@link COSBase} to check.
+ * @return {@code true}, if the given {@link COSBase} is already known to and has been processed by this
+ * {@link COSIncrement}.
+ * @see #objects
+ * @see #processedObjects
+ */
+ public boolean contains(COSBase base)
+ {
+ return objects.contains(base) || (base instanceof COSObject && processedObjects.contains((COSObject) base));
+ }
+
+ /**
+ * Check whether the given {@link COSUpdateState}´s {@link COSDocumentState} differs from the {@link COSIncrement}´s
+ * known {@link #incrementOrigin}.<br>
+ * Should that be the case, the {@link COSUpdateState} originates from another {@link COSDocument} and must be added
+ * to the {@link COSIncrement}, hence call {@link COSUpdateState#update()}.
+ *
+ * @param updateState The {@link COSUpdateState} that shall be updated, if it's originating from another
+ * {@link COSDocument}.
+ * @see #incrementOrigin
+ */
+ private void updateDifferentOrigin(COSUpdateState updateState)
+ {
+ if(incrementOrigin != null && updateState != null &&
+ incrementOrigin.getUpdateState().getOriginDocumentState() != updateState.getOriginDocumentState())
+ {
+ updateState.update();
+ }
+ }
+
+ /**
+ * The given object and actual {COSBase}s shall be part of the increment and must be added to {@link #objects},
+ * if possible.<br>
+ * {@code null} values shall be skipped.
+ *
+ * @param object The {@link COSBase} to add to {@link #objects}.
+ * @see #objects
+ */
+ private void add(COSBase object)
+ {
+ if(object != null)
+ {
+ objects.add(object);
+ }
+ }
+
+ /**
+ * The given {@link COSObject} has been processed, or is being processed. It shall be added to
+ * {@link #processedObjects} to skip it, should it be encountered again.<br>
+ * {@code null} values shall be ignored.
+ *
+ * @param base The {@link COSObject} to add to {@link #processedObjects}.
+ * @see #processedObjects
+ */
+ private void addProcessedObject(COSObject base)
+ {
+ if(base != null)
+ {
+ processedObjects.add(base);
+ }
+ }
+
+ /**
+ * The given {@link COSBase}s are not fit for inclusion in an increment and shall be added to {@link #excluded}.<br>
+ * {@code null} values shall be ignored.
+ *
+ * @param base The {@link COSBase}s to add to {@link #excluded}.
+ * @return The {@link COSIncrement} itself, to allow method chaining.
+ * @see #excluded
+ */
+ public COSIncrement exclude(COSBase... base)
+ {
+ if(base != null)
+ {
+ excluded.addAll(Arrays.asList(base));
+ }
+ return this;
+ }
+
+ /**
+ * Returns {@code true}, if the given {@link COSBase} has been excluded from the increment, and hence is contained
+ * in {@link #excluded}.
+ *
+ * @param base The {@link COSBase} to check for exclusion.
+ * @return {@code true}, if the given {@link COSBase} has been excluded from the increment, and hence is contained
+ * in {@link #excluded}.
+ * @see #excluded
+ */
+ private boolean isExcluded(COSBase base)
+ {
+ return excluded.contains(base);
+ }
+
+ /**
+ * Returns all indirect {@link COSBase}s, that shall be written to an increment as top level {@link COSObject}s.<br>
+ * Calling this method will cause the increment to be initialized.
+ *
+ * @return All indirect {@link COSBase}s, that shall be written to an increment as top level {@link COSObject}s.
+ * @see #objects
+ */
+ public Set<COSBase> getObjects()
+ {
+ if(!initialized && incrementOrigin != null)
+ {
+ collect(incrementOrigin.getCOSObject());
+ initialized = true;
+ }
+ return objects;
+ }
+
+ /**
+ * Return an iterator for the determined {@link #objects} contained in this {@link COSIncrement}.
+ *
+ * @return An iterator for the determined {@link #objects} contained in this {@link COSIncrement}.
+ */
+ @Override
+ public Iterator<COSBase> iterator()
+ {
+ return getObjects().iterator();
+ }
+
+}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObject.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSObject.java Sun Oct 3 13:24:54 2021
@@ -20,8 +20,6 @@ import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.observer.event.COSDereferenceEvent;
-import org.apache.pdfbox.cos.observer.event.COSRemoveEvent;
/**
* This class represents a PDF object.
@@ -36,7 +34,8 @@ public class COSObject extends COSBase i
private int generationNumber;
private ICOSParser parser;
private boolean isDereferenced = false;
-
+ private final COSUpdateState updateState;
+
private static final Log LOG = LogFactory.getLog(COSObject.class);
/**
@@ -47,9 +46,9 @@ public class COSObject extends COSBase i
*/
public COSObject(COSBase object)
{
+ updateState = new COSUpdateState(this);
baseObject = object;
isDereferenced = true;
- reportUpdate(new COSDereferenceEvent<>(this, baseObject));
}
/**
@@ -63,7 +62,6 @@ public class COSObject extends COSBase i
this(objectKey, null);
baseObject = object;
isDereferenced = true;
- reportUpdate(new COSDereferenceEvent<>(this, baseObject));
}
/**
@@ -75,11 +73,9 @@ public class COSObject extends COSBase i
*/
public COSObject(COSBase object, ICOSParser parser)
{
+ updateState = new COSUpdateState(this);
baseObject = object;
isDereferenced = object != null;
- if (isDereferenced) {
- reportUpdate(new COSDereferenceEvent<>(this, baseObject));
- }
this.parser = parser;
}
@@ -92,6 +88,7 @@ public class COSObject extends COSBase i
*/
public COSObject(COSObjectKey key, ICOSParser parser)
{
+ updateState = new COSUpdateState(this);
this.parser = parser;
objectNumber = key.getNumber();
generationNumber = key.getGeneration();
@@ -122,7 +119,7 @@ public class COSObject extends COSBase i
// mark as dereferenced to avoid endless recursions
isDereferenced = true;
baseObject = parser.dereferenceCOSObject(this);
- reportUpdate(new COSDereferenceEvent<>(this, baseObject));
+ getUpdateState().dereferenceChild(baseObject);
}
catch (IOException e)
{
@@ -143,7 +140,7 @@ public class COSObject extends COSBase i
{
if(baseObject != null)
{
- reportUpdate(new COSRemoveEvent<>(this, baseObject));
+ getUpdateState().update();
}
baseObject = COSNull.NULL;
parser = null;
@@ -199,5 +196,17 @@ public class COSObject extends COSBase i
{
return isDereferenced;
}
-
+
+ /**
+ * Returns the current {@link COSUpdateState} of this {@link COSObject}.
+ *
+ * @return The current {@link COSUpdateState} of this {@link COSObject}.
+ * @see COSUpdateState
+ */
+ @Override
+ public COSUpdateState getUpdateState()
+ {
+ return updateState;
+ }
+
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfo.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfo.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfo.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateInfo.java Sun Oct 3 13:24:54 2021
@@ -16,11 +16,9 @@
*/
package org.apache.pdfbox.cos;
-import org.apache.pdfbox.cos.observer.COSIncrementObserver;
-import org.apache.pdfbox.cos.observer.event.COSDirectUpdateEvent;
-import org.apache.pdfbox.cos.observer.COSObserver;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
-public interface COSUpdateInfo
+public interface COSUpdateInfo extends COSObjectable
{
/**
@@ -31,21 +29,7 @@ public interface COSUpdateInfo
*/
default boolean isNeedToBeUpdated()
{
- COSBase instance = getCOSObject();
- if (instance != null)
- {
- for (COSObserver observer : instance.getRegisteredObservers())
- {
- if (observer instanceof COSIncrementObserver)
- {
- if (((COSIncrementObserver) observer).isNeedToBeUpdated(instance))
- {
- return true;
- }
- }
- }
- }
- return false;
+ return getUpdateState().isUpdated();
}
/**
@@ -56,19 +40,26 @@ public interface COSUpdateInfo
*/
default void setNeedToBeUpdated(boolean flag)
{
- COSBase instance = getCOSObject();
- if (instance != null)
- {
- instance.reportUpdate(new COSDirectUpdateEvent<>(instance, flag));
- }
+ getUpdateState().update(flag);
}
-
+
/**
- * Convert this standard java object to a COS object.
+ * Uses this {@link COSUpdateInfo} as the base object of a new {@link COSIncrement}.
*
- * @return The cos object that matches this Java object.
- * @see COSBase#getCOSObject()
+ * @return A {@link COSIncrement} based on this {@link COSUpdateInfo}.
+ * @see COSIncrement
*/
- COSBase getCOSObject();
-
+ default COSIncrement toIncrement()
+ {
+ return getUpdateState().toIncrement();
+ }
+
+ /**
+ * Returns the current {@link COSUpdateState} of this {@link COSUpdateInfo}.
+ *
+ * @return The current {@link COSUpdateState} of this {@link COSUpdateInfo}.
+ * @see COSUpdateState
+ */
+ COSUpdateState getUpdateState();
+
}
\ No newline at end of file
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateState.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateState.java?rev=1893854&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateState.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSUpdateState.java Sun Oct 3 13:24:54 2021
@@ -0,0 +1,344 @@
+/*
+ * 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.cos;
+
+/**
+ * A {@link COSUpdateState} instance manages update states for a {@link COSUpdateInfo}. Such states are used to create
+ * a {@link COSIncrement} for the incremental saving of a {@link COSDocument}.
+ *
+ * @author Christian Appl
+ * @see COSDocumentState
+ * @see COSUpdateInfo
+ * @see COSIncrement
+ */
+public class COSUpdateState
+{
+
+ /**
+ * The {@link COSUpdateInfo} the {@link COSUpdateState} does manage update states for.
+ */
+ private final COSUpdateInfo updateInfo;
+ /**
+ * The {@link COSDocumentState} the {@link #updateInfo} is linked to.
+ */
+ private COSDocumentState originDocumentState = null;
+ /**
+ * The actual update state of {@link #updateInfo}.
+ * <ul>
+ * <li>{@code true}, if {@link #updateInfo} has been updated after the document completed parsing.</li>
+ * <li>{@code false}, if {@link #updateInfo} has remained unaltered since the document completed parsing.</li>
+ * </ul>
+ */
+ private boolean updated = false;
+
+ /**
+ * Creates a new {@link COSUpdateState} for the given {@link COSUpdateInfo}.
+ *
+ * @param updateInfo The {@link COSUpdateInfo}, that shall be managed by this {@link COSUpdateState}.
+ */
+ public COSUpdateState(COSUpdateInfo updateInfo)
+ {
+ this.updateInfo = updateInfo;
+ }
+
+ /**
+ * <p>
+ * Links the given {@link COSDocumentState} to the {@link #updated} state of the managed {@link #updateInfo}.<br>
+ * </p>
+ * <p>
+ * This shall also initialize {@link #updated} accordingly and will also set the same {@link COSDocumentState} for
+ * all possibly contained substructures.
+ * </p>
+ * <p>
+ * Should {@link #originDocumentState} already have been set, by a prior call to this method, this shall deny to
+ * overwrite it.
+ * </p>
+ * <p>
+ * {@link COSDocumentState#isAcceptingUpdates()} shall determine, whether updates to {@link #updateInfo} are
+ * allowed.
+ * </p>
+ * <p>
+ * As long as no {@link COSDocumentState} is linked to this {@link COSUpdateState}, it shall not accept updates.
+ * </p>
+ *
+ * @param originDocumentState The {@link COSDocumentState} that shall be linked to this {@link COSUpdateState}.
+ * @see #originDocumentState
+ * @see #updated
+ */
+ public void setOriginDocumentState(COSDocumentState originDocumentState)
+ {
+ setOriginDocumentState(originDocumentState, false);
+ }
+
+ /**
+ * <p>
+ * Links the given {@link COSDocumentState} to the {@link #updated} state of the managed {@link #updateInfo}.<br>
+ * </p>
+ * <p>
+ * This shall also initialize {@link #updated} accordingly and will also set the same {@link COSDocumentState} for
+ * all possibly contained substructures.
+ * </p>
+ * <p>
+ * Should {@link #originDocumentState} already have been set, by a prior call to this method, this shall deny to
+ * overwrite it.
+ * </p>
+ * <p>
+ * {@link COSDocumentState#isAcceptingUpdates()} shall determine, whether updates to {@link #updateInfo} are
+ * allowed.
+ * </p>
+ * <p>
+ * As long as no {@link COSDocumentState} is linked to this {@link COSUpdateState}, it shall not accept updates.
+ * </p>
+ * <p>
+ * Additionally to {@link #setOriginDocumentState(COSDocumentState)}, this shall also deny changing
+ * {@link #updated}, should the flag {@code dereferencing} indicate, that this is caused by dereferencing a
+ * {@link COSObject}.
+ * </p>
+ *
+ * @param originDocumentState The {@link COSDocumentState} that shall be linked to this {@link COSUpdateState}.
+ * @param dereferencing {@code true}, if this update of the {@link COSDocumentState} is caused by
+ * dereferencing a {@link COSObject}.
+ * @see #originDocumentState
+ * @see #updated
+ */
+ private void setOriginDocumentState(COSDocumentState originDocumentState, boolean dereferencing)
+ {
+ if(this.originDocumentState != null || originDocumentState == null)
+ {
+ return;
+ }
+ this.originDocumentState = originDocumentState;
+ if(!dereferencing)
+ {
+ update();
+ }
+
+ if(updateInfo instanceof COSDictionary)
+ {
+ COSDictionary dictionary = (COSDictionary) updateInfo;
+ for(COSBase entry : dictionary.getValues())
+ {
+ if(!(entry instanceof COSUpdateInfo))
+ {
+ continue;
+ }
+ ((COSUpdateInfo) entry).getUpdateState().setOriginDocumentState(originDocumentState, dereferencing);
+ }
+ }
+ else if(updateInfo instanceof COSArray)
+ {
+ COSArray array = (COSArray) updateInfo;
+ for(COSBase entry : array)
+ {
+ if(!(entry instanceof COSUpdateInfo))
+ {
+ continue;
+ }
+ ((COSUpdateInfo) entry).getUpdateState().setOriginDocumentState(originDocumentState, dereferencing);
+ }
+ }
+ else if(updateInfo instanceof COSObject)
+ {
+ COSObject object = (COSObject) updateInfo;
+ COSBase reference;
+ if(object.isDereferenced() && (reference = object.getObject()) instanceof COSUpdateInfo)
+ {
+ ((COSUpdateInfo) reference).getUpdateState().setOriginDocumentState(originDocumentState, dereferencing);
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Returns the {@link #originDocumentState}, that is linked to the managed {@link #updateInfo}.
+ * </p>
+ * <p>
+ * {@link COSDocumentState#isAcceptingUpdates()} shall determine, whether updates to {@link #updateInfo} are
+ * allowed.
+ * </p>
+ * <p>
+ * As long as no {@link COSDocumentState} is linked to this {@link COSUpdateState}, it shall not accept updates.
+ * </p>
+ *
+ * @return The {@link COSDocumentState} linked to this {@link COSUpdateState}.
+ * @see #setOriginDocumentState(COSDocumentState)
+ */
+ public COSDocumentState getOriginDocumentState()
+ {
+ return originDocumentState;
+ }
+
+ /**
+ * Returns {@code true}, if the linked {@link #originDocumentState} {@link COSDocumentState#isAcceptingUpdates()}
+ * and such a {@link COSDocumentState} has been linked to this {@link COSUpdateState}.
+ *
+ * @return {@code true}, if the linked {@link #originDocumentState} {@link COSDocumentState#isAcceptingUpdates()}
+ * and such a {@link COSDocumentState} has been linked to this {@link COSUpdateState}.
+ * @see #originDocumentState
+ * @see COSDocumentState#isAcceptingUpdates()
+ */
+ boolean isAcceptingUpdates()
+ {
+ return originDocumentState != null && originDocumentState.isAcceptingUpdates();
+ }
+
+ /**
+ * Returns the actual {@link #updated} state of the managed {@link #updateInfo}.
+ *
+ * @return The actual {@link #updated} state of the managed {@link #updateInfo}
+ * @see #updated
+ */
+ public boolean isUpdated()
+ {
+ return updated;
+ }
+
+ /**
+ * Calls {@link #update(boolean)} with {@code true} as the new update state.<br>
+ * This shall only then have an effect, if {@link #isAcceptingUpdates()} returns {@code true}.
+ *
+ * @see #update(boolean)
+ * @see #updated
+ * @see #isAcceptingUpdates()
+ */
+ void update()
+ {
+ update(true);
+ }
+
+ /**
+ * Sets the {@link #updated} state of the managed {@link #updateInfo} to the given state.<br>
+ * This shall only then have an effect, if {@link #isAcceptingUpdates()} returns {@code true}.
+ *
+ * @param updated The state to set for {@link #updated}.
+ * @see #update(boolean)
+ * @see #updated
+ * @see #isAcceptingUpdates()
+ */
+ void update(boolean updated)
+ {
+ if(isAcceptingUpdates())
+ {
+ this.updated = updated;
+ }
+ }
+
+ /**
+ * <p>
+ * Shall call {@link #update()} for this {@link COSUpdateState} and shall
+ * {@link #setOriginDocumentState(COSDocumentState)} for the given child, initializing it´s {@link #updated} state
+ * and {@link #originDocumentState}.
+ * </p>
+ * <p>
+ * This shall have no effect for a child, that is not an instance of {@link COSUpdateInfo}.
+ * </p>
+ *
+ * @param child The child that shall also be updated.
+ * @see #update()
+ * @see #setOriginDocumentState(COSDocumentState)
+ */
+ void update(COSBase child)
+ {
+ update();
+ if(child instanceof COSUpdateInfo)
+ {
+ ((COSUpdateInfo) child).getUpdateState().setOriginDocumentState(originDocumentState);
+ }
+ }
+
+ /**
+ * <p>
+ * Shall call {@link #update()} for this {@link COSUpdateState} and shall
+ * {@link #setOriginDocumentState(COSDocumentState)} for the given children, initializing their {@link #updated}
+ * state and {@link #originDocumentState}.
+ * </p>
+ * <p>
+ * This shall have no effect for a child, that is not an instance of {@link COSUpdateInfo}.
+ * </p>
+ *
+ * @param children The children that shall also be updated.
+ * @see #update()
+ * @see #setOriginDocumentState(COSDocumentState)
+ */
+ void update(COSArray children)
+ {
+ update((Iterable<COSBase>) children);
+ }
+
+ /**
+ * <p>
+ * Shall call {@link #update()} for this {@link COSUpdateState} and shall
+ * {@link #setOriginDocumentState(COSDocumentState)} for the given children, initializing their {@link #updated}
+ * state and {@link #originDocumentState}.
+ * </p>
+ * <p>
+ * This shall have no effect for a child, that is not an instance of {@link COSUpdateInfo}.
+ * </p>
+ *
+ * @param children The children that shall also be updated.
+ * @see #update()
+ * @see #setOriginDocumentState(COSDocumentState)
+ */
+ void update(Iterable<COSBase> children)
+ {
+ update();
+ if(children == null)
+ {
+ return;
+ }
+ for(COSBase child : children)
+ {
+ if(child instanceof COSUpdateInfo)
+ {
+ ((COSUpdateInfo) child).getUpdateState().setOriginDocumentState(originDocumentState);
+ }
+ }
+ }
+
+ /**
+ * This shall {@link #setOriginDocumentState(COSDocumentState, boolean)} for the dereferenced child,
+ * initializing it´s {@link #originDocumentState}.
+ * </p>
+ * <p>
+ * This shall have no effect for a child, that is not an instance of {@link COSUpdateInfo} and will never change
+ * the child´s {@link #updated} state.
+ * </p>
+ *
+ * @param child The child, that has been dereferenced.
+ * @see #setOriginDocumentState(COSDocumentState, boolean)
+ */
+ void dereferenceChild(COSBase child)
+ {
+ if(child instanceof COSUpdateInfo)
+ {
+ ((COSUpdateInfo) child).getUpdateState().setOriginDocumentState(originDocumentState, true);
+ }
+ }
+
+ /**
+ * Uses the managed {@link #updateInfo} as the base object of a new {@link COSIncrement}.
+ *
+ * @return A {@link COSIncrement} based on the managed {@link #updateInfo}.
+ * @see COSUpdateInfo
+ * @see COSIncrement
+ */
+ COSIncrement toIncrement()
+ {
+ return new COSIncrement(updateInfo);
+ }
+
+}
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=1893854&r1=1893853&r2=1893854&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 Oct 3 13:24:54 2021
@@ -41,7 +41,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSBoolean;
@@ -1469,14 +1468,10 @@ public class COSWriter implements ICOSVi
public void write(PDDocument doc, SignatureInterface signInterface) throws IOException
{
pdDocument = doc;
- // Whatever the writer wishes to change, the writer itself shall keep track of it.
- pdDocument.getDocument().getUpdateObserver().stopTrackingChanges();
- if (incrementalUpdate)
- {
- for(COSUpdateInfo updatedObject : pdDocument.getDocument().getUpdateObserver())
- {
- addObjectToWrite(updatedObject.getCOSObject());
- }
+ COSDocument cosDoc = pdDocument.getDocument();
+ COSDictionary trailer = cosDoc.getTrailer();
+ if(incrementalUpdate){
+ trailer.toIncrement().exclude(trailer).forEach(objectsToWrite::add);
}
signatureInterface = signInterface;
number = pdDocument.getDocument().getHighestXRefObjectNumber();
@@ -1486,8 +1481,6 @@ public class COSWriter implements ICOSVi
}
Long idTime = pdDocument.getDocumentId() == null ? System.currentTimeMillis()
: pdDocument.getDocumentId();
- COSDocument cosDoc = pdDocument.getDocument();
- COSDictionary trailer = cosDoc.getTrailer();
// if the document says we should remove encryption, then we shouldn't encrypt
if (doc.isAllSecurityToBeRemoved())
@@ -1582,17 +1575,12 @@ public class COSWriter implements ICOSVi
public void write(FDFDocument doc) throws IOException
{
fdfDocument = doc;
- // Whatever the writer wishes to change, the writer itself shall keep track of it.
- fdfDocument.getDocument().getUpdateObserver().stopTrackingChanges();
- if (incrementalUpdate)
- {
- for(COSUpdateInfo updatedObject : pdDocument.getDocument().getUpdateObserver())
- {
- addObjectToWrite(updatedObject.getCOSObject());
- }
+ COSDocument cosDoc = fdfDocument.getDocument();
+ COSDictionary trailer = cosDoc.getTrailer();
+ if(incrementalUpdate){
+ trailer.toIncrement().exclude(trailer).forEach(objectsToWrite::add);
}
willEncrypt = false;
- COSDocument cosDoc = fdfDocument.getDocument();
cosDoc.accept(this);
}
/**
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Sun Oct 3 13:24:54 2021
@@ -168,7 +168,7 @@ public class PDDocument implements Close
public PDDocument(MemoryUsageSetting memUsageSetting)
{
document = new COSDocument(memUsageSetting);
- document.getUpdateObserver().startTrackingChanges();
+ document.getDocumentState().setParsing(false);
pdfSource = null;
// First we need a trailer
@@ -222,7 +222,7 @@ public class PDDocument implements Close
public PDDocument(COSDocument doc, RandomAccessRead source, AccessPermission permission)
{
document = doc;
- document.getUpdateObserver().startTrackingChanges();
+ document.getDocumentState().setParsing(false);
pdfSource = source;
accessPermission = permission;
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDocument.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDocument.java Sun Oct 3 13:24:54 2021
@@ -50,6 +50,7 @@ public class FDFDocument implements Clos
public FDFDocument()
{
document = new COSDocument();
+ document.getDocumentState().setParsing(false);
document.setVersion(1.2f);
// First we need a trailer
@@ -68,6 +69,7 @@ public class FDFDocument implements Clos
public FDFDocument(COSDocument doc)
{
document = doc;
+ document.getDocumentState().setParsing(false);
}
/**
Copied: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSIncrement.java (from r1893853, pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java)
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSIncrement.java?p2=pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSIncrement.java&p1=pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java&r1=1893853&r2=1893854&rev=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfoObserver.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSIncrement.java Sun Oct 3 13:24:54 2021
@@ -45,7 +45,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.ConcurrentModificationException;
-class TestCOSUpdateInfoObserver
+class TestCOSIncrement
{
// TODO Very basic and primitive test - add in depth testing for all this.
@@ -120,7 +120,7 @@ class TestCOSUpdateInfoObserver
assertNull(document.getPage(1).getResources(), "Page 2 should not have contained resources");
try (PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(0)))
{
- URL imageResource = TestCOSUpdateInfoObserver.class.getResource("simple.png");
+ URL imageResource = TestCOSIncrement.class.getResource("simple.png");
assertNotNull(imageResource, "Image resource not found.");
File image = assertDoesNotThrow(() -> new File(imageResource.toURI()),
"Image file could not be loaded");
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfo.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfo.java?rev=1893854&r1=1893853&r2=1893854&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfo.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/cos/TestCOSUpdateInfo.java Sun Oct 3 13:24:54 2021
@@ -34,12 +34,13 @@ class TestCOSUpdateInfo
@Test
void testIsSetNeedToBeUpdate()
{
- COSUpdateInfoObserver observer = new COSUpdateInfoObserver(null);
- observer.startTrackingChanges();
-
+ COSDocumentState origin = new COSDocumentState();
+ origin.setParsing(false);
// COSDictionary
COSUpdateInfo testCOSDictionary = new COSDictionary();
- observer.monitor(testCOSDictionary.getCOSObject());
+ testCOSDictionary.setNeedToBeUpdated(true);
+ assertFalse(testCOSDictionary.isNeedToBeUpdated());
+ testCOSDictionary.getUpdateState().setOriginDocumentState(origin);
testCOSDictionary.setNeedToBeUpdated(true);
assertTrue(testCOSDictionary.isNeedToBeUpdated());
testCOSDictionary.setNeedToBeUpdated(false);
@@ -48,7 +49,9 @@ class TestCOSUpdateInfo
// COSObject
COSUpdateInfo testCOSObject;
testCOSObject = new COSObject(null);
- observer.monitor(testCOSObject.getCOSObject());
+ testCOSObject.setNeedToBeUpdated(true);
+ assertFalse(testCOSObject.isNeedToBeUpdated());
+ testCOSObject.getUpdateState().setOriginDocumentState(origin);
testCOSObject.setNeedToBeUpdated(true);
assertTrue(testCOSObject.isNeedToBeUpdated());
testCOSObject.setNeedToBeUpdated(false);