Skip to content

Commit

Permalink
PDFBOX-5263: enhance incremental saving as suggested by Christian Appl
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1893246 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Maruan Sahyoun committed Sep 11, 2021
1 parent a00b024 commit 4ed06d6
Show file tree
Hide file tree
Showing 21 changed files with 1,576 additions and 68 deletions.
70 changes: 45 additions & 25 deletions pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
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;

/**
Expand All @@ -34,7 +37,6 @@
public class COSArray extends COSBase implements Iterable<COSBase>, COSUpdateInfo
{
private final List<COSBase> objects = new ArrayList<>();
private boolean needToBeUpdated;

/**
* Constructor.
Expand All @@ -57,6 +59,7 @@ public COSArray(List<? extends COSObjectable> cosObjectables)
}
cosObjectables.forEach(cosObjectable ->
objects.add(cosObjectable != null ? cosObjectable.getCOSObject() : null));
reportUpdate(new COSAddEvent<>(this, objects));
}

/**
Expand All @@ -67,6 +70,7 @@ public COSArray(List<? extends COSObjectable> cosObjectables)
public void add( COSBase object )
{
objects.add( object );
reportUpdate(new COSAddEvent<>(this, object));
}

/**
Expand All @@ -77,6 +81,7 @@ public void add( COSBase object )
public void add( COSObjectable object )
{
objects.add( object.getCOSObject() );
reportUpdate(new COSAddEvent<>(this, object.getCOSObject()));
}

/**
Expand All @@ -89,14 +94,17 @@ public void add( COSObjectable object )
public void add( int i, COSBase object)
{
objects.add( i, object );
reportUpdate(new COSAddEvent<>(this, object));
}

/**
* This will remove all of the objects in the collection.
*/
public void clear()
{
List<COSBase> removed = new ArrayList<>(objects);
objects.clear();
reportUpdate(new COSRemoveEvent<>(this, removed));
}

/**
Expand All @@ -107,6 +115,7 @@ public void clear()
public void removeAll( Collection<COSBase> objectsList )
{
objects.removeAll( objectsList );
reportUpdate(new COSRemoveEvent<>(this, objectsList));
}

/**
Expand All @@ -116,7 +125,10 @@ public void removeAll( Collection<COSBase> objectsList )
*/
public void retainAll( Collection<COSBase> objectsList )
{
List<COSBase> removed = new ArrayList<>(this.objects);
removed.removeAll(objectsList);
objects.retainAll( objectsList );
reportUpdate(new COSRemoveEvent<>(this, removed));
}

/**
Expand All @@ -127,6 +139,7 @@ public void retainAll( Collection<COSBase> objectsList )
public void addAll( Collection<COSBase> objectsList )
{
objects.addAll( objectsList );
reportUpdate(new COSAddEvent<>(this, objectsList));
}

/**
Expand All @@ -139,6 +152,7 @@ public void addAll( COSArray objectList )
if( objectList != null )
{
objects.addAll( objectList.objects );
reportUpdate(new COSAddEvent<>(this, objectList));
}
}

Expand All @@ -152,6 +166,7 @@ public void addAll( COSArray objectList )
public void addAll( int i, Collection<COSBase> objectList )
{
objects.addAll( i, objectList );
reportUpdate(new COSAddEvent<>(this, objectList));
}

/**
Expand All @@ -162,7 +177,13 @@ public void addAll( int i, Collection<COSBase> objectList )
*/
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));
}

/**
Expand All @@ -173,7 +194,14 @@ public void set( int index, COSBase object )
*/
public void set( int index, int intVal )
{
objects.set( index, COSInteger.get(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));
}

/**
Expand All @@ -184,12 +212,18 @@ public void set( int index, int intVal )
*/
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));
}

/**
Expand Down Expand Up @@ -379,7 +413,9 @@ public int size()
*/
public COSBase remove( int i )
{
return objects.remove( i );
COSBase removedEntry = objects.remove( i );
reportUpdate(new COSRemoveEvent<>(this, removedEntry));
return removedEntry;
}

/**
Expand All @@ -392,7 +428,9 @@ public COSBase remove( int i )
*/
public boolean remove( COSBase o )
{
return objects.remove( o );
boolean removed = objects.remove( o );
reportUpdate(new COSRemoveEvent<>(this, o));
return removed;
}

/**
Expand Down Expand Up @@ -520,10 +558,13 @@ public void growToSize( int size )
*/
public void growToSize( int size, COSBase object )
{
List<COSBase> addedObjects = new ArrayList<>();
while( size() < size )
{
add( object );
addedObjects.add(object);
}
reportUpdate(new COSAddEvent<>(this, addedObjects));
}

/**
Expand All @@ -539,27 +580,6 @@ public Object accept(ICOSVisitor visitor) throws IOException
return visitor.visitFromArray(this);
}

@Override
public boolean isNeedToBeUpdated()
{
return needToBeUpdated;
}

/**
* {@inheritDoc}
*<p>
* Although the state is set, it has no effect on COSWriter behavior because arrays are always
* written as direct object. If an array is to be part of an incremental save, then the method
* should be called for its holding dictionary.
*
* @param flag
*/
@Override
public void setNeedToBeUpdated(boolean flag)
{
needToBeUpdated = flag;
}

/**
* This will take an COSArray of numbers and convert it to a float[].
*
Expand Down
58 changes: 57 additions & 1 deletion pdfbox/src/main/java/org/apache/pdfbox/cos/COSBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
*/
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.ArrayList;
import java.util.List;

/**
* The base object that all objects in the PDF document will extend.
Expand All @@ -27,6 +32,8 @@
*/
public abstract class COSBase implements COSObjectable
{

private final List<COSObserver> cosChangeObservers = new ArrayList<>();
private boolean direct;
private COSObjectKey key;

Expand Down Expand Up @@ -75,7 +82,10 @@ public boolean isDirect()
*/
public void setDirect(boolean direct)
{
this.direct = direct;
this.direct = direct;
if(direct){
reportUpdate(new COSDirectObjectEvent<>(this));
}
}

/**
Expand All @@ -98,4 +108,50 @@ public void setKey(COSObjectKey key)
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);
}
}

}
36 changes: 22 additions & 14 deletions pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
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;
Expand All @@ -48,9 +51,8 @@ public class COSDictionary extends COSBase implements COSUpdateInfo
* Log instance.
*/
private static final Log LOG = LogFactory.getLog(COSDictionary.class);

private static final String PATH_SEPARATOR = "/";
private boolean needToBeUpdated;

/**
* The name-value pairs of this dictionary. The pairs are kept in the order they were added to the dictionary.
Expand All @@ -73,6 +75,7 @@ public COSDictionary()
public COSDictionary(COSDictionary dict)
{
items.putAll(dict.items);
reportUpdate(new COSAddEvent<>(this, items.values()));
}

/**
Expand Down Expand Up @@ -128,7 +131,9 @@ public int size()
*/
public void clear()
{
List<COSBase> removed = new ArrayList<>(items.values());
items.clear();
reportUpdate(new COSRemoveEvent<>(this, removed));
}

/**
Expand Down Expand Up @@ -201,7 +206,20 @@ public void setItem(COSName key, COSBase value)
}
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));
}
}
}

Expand Down Expand Up @@ -1150,7 +1168,9 @@ public boolean getFlag(COSName field, int bitFlag)
*/
public void removeItem(COSName key)
{
COSBase removed = getItem(key);
items.remove(key);
reportUpdate(new COSRemoveEvent<>(this, removed));
}

/**
Expand Down Expand Up @@ -1255,18 +1275,6 @@ public Object accept(ICOSVisitor visitor) throws IOException
{
return visitor.visitFromDictionary(this);
}

@Override
public boolean isNeedToBeUpdated()
{
return needToBeUpdated;
}

@Override
public void setNeedToBeUpdated(boolean flag)
{
needToBeUpdated = flag;
}

/**
* This will add all of the dictionaries keys/values to this dictionary. Existing key/value pairs will be
Expand Down
Loading

0 comments on commit 4ed06d6

Please sign in to comment.