diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/Dictionary.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/Dictionary.java index bd8c2ca88..e10492e56 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/Dictionary.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/Dictionary.java @@ -161,6 +161,14 @@ public int getInt(Name key) { return library.getInt(entries, key); } + public Reference getReference(Name key) { + Object o = entries.get(key); + if (o instanceof Reference) { + return (Reference) o; + } + return null; + } + public List getList(Name key) { Object o = getObject(key); if (o instanceof List) { diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/Document.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/Document.java index 950459632..56d593a7b 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/Document.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/Document.java @@ -347,7 +347,7 @@ private void setInputStream(ByteBuffer input) input = header.parseHeader(input); library.setDocumentByteBuffer(input); - library.setFileVersion(header.getVersion()); + library.setFileHeader(header); // create instance of CrossReferenceRoot as we may need it the trailer can't be correctly decoded. crossReferenceRoot = new CrossReferenceRoot(library); @@ -366,13 +366,13 @@ private void setInputStream(ByteBuffer input) crossReferenceRoot.initialize(input); library.setCrossReferenceRoot(crossReferenceRoot); } catch (Exception e) { - crossReferenceRoot.setLazyInitializationFailed(true); + crossReferenceRoot.setInitializationFailed(true); logger.log(Level.WARNING, "Cross reference loading failed, reindexing file.", e); } } // linear traversal of file. - if (trailer.isLazyInitializationFailed() || crossReferenceRoot.isLazyInitializationFailed()) { + if (trailer.isLazyInitializationFailed() || crossReferenceRoot.isInitializationFailed()) { crossReferenceRoot = library.rebuildCrossReferenceTable(); library.setCrossReferenceRoot(crossReferenceRoot); } diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/StateManager.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/StateManager.java index 4298b0b2c..d72258b95 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/StateManager.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/StateManager.java @@ -131,7 +131,6 @@ public Change getChange(Reference reference) { if (change != null) { return change; } else { - logger.warning("No change object was found for " + reference); return null; } } @@ -233,7 +232,7 @@ else if (aron > bron) } } - protected enum Type { + public enum Type { SYNTHETIC, CHANGE, DELETE diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReference.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReference.java index e2db13648..f16f074fc 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReference.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReference.java @@ -9,6 +9,7 @@ import org.icepdf.core.util.parser.object.ObjectLoader; import java.io.IOException; +import java.util.HashMap; public interface CrossReference { @@ -18,6 +19,8 @@ PObject loadObject(ObjectLoader objectLoader, Reference reference, Name hint) CrossReferenceEntry getEntry(Reference reference) throws ObjectStateException, CrossReferenceStateException, IOException; + HashMap getEntries(); + int getXrefStartPos(); DictionaryEntries getDictionaryEntries(); diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceBase.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceBase.java index 198254343..b28cc229a 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceBase.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceBase.java @@ -9,6 +9,7 @@ import org.icepdf.core.util.parser.object.Parser; import java.io.IOException; +import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; /** @@ -19,7 +20,7 @@ public abstract class CrossReferenceBase implements CrossR public final T crossReference; protected final ConcurrentHashMap indirectObjectReferences; - protected CrossReference prefCrossReference; + protected CrossReference prevCrossReference; protected int xrefStartPos; @@ -42,8 +43,8 @@ public CrossReferenceEntry getEntry(Reference reference) throws ObjectStateExcep DictionaryEntries entries = crossReference.getEntries(); Library library = crossReference.getLibrary(); if (crossReferenceEntry == null && entries.get(PTrailer.PREV_KEY) != null) { - if (prefCrossReference != null) { - return prefCrossReference.getEntry(reference); + if (prevCrossReference != null) { + return prevCrossReference.getEntry(reference); } else { // try finding the entry in the previous table Parser parser = new Parser(library); @@ -51,8 +52,8 @@ public CrossReferenceEntry getEntry(Reference reference) throws ObjectStateExcep CrossReference crossReference = parser.getCrossReference( library.getMappedFileByteBuffer(), this.crossReference.getInt(PTrailer.PREV_KEY)); if (crossReference != null) { - prefCrossReference = crossReference; - return prefCrossReference.getEntry(reference); + prevCrossReference = crossReference; + return prevCrossReference.getEntry(reference); } } } @@ -60,6 +61,16 @@ public CrossReferenceEntry getEntry(Reference reference) throws ObjectStateExcep return crossReferenceEntry; } + public HashMap getEntries() { + HashMap completeIndirectReferences = new HashMap<>(indirectObjectReferences.size()); + if (prevCrossReference != null) { + completeIndirectReferences.putAll(prevCrossReference.getEntries()); + } + // current after previous so we get the most recent object + completeIndirectReferences.putAll(indirectObjectReferences); + return completeIndirectReferences; + } + public CrossReferenceEntry getEntryNoDescendents(Reference reference) { return indirectObjectReferences.get(reference); } diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceRoot.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceRoot.java index 263b26af6..1e3e7ba65 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceRoot.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceRoot.java @@ -29,7 +29,7 @@ public class CrossReferenceRoot { private final ArrayList crossReferences; - private boolean lazyInitializationFailed; + private boolean initializationFailed; public CrossReferenceRoot(Library library) { this.library = library; @@ -115,12 +115,12 @@ public PObject loadObject(ObjectLoader objectLoader, Reference reference, Name h return null; } - public void setLazyInitializationFailed(boolean failed) { - lazyInitializationFailed = failed; + public void setInitializationFailed(boolean failed) { + initializationFailed = failed; } - public boolean isLazyInitializationFailed() { - return lazyInitializationFailed; + public boolean isInitializationFailed() { + return initializationFailed; } public void addCrossReference(CrossReference crossReferenceTable) { diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceTable.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceTable.java index 0f8faccde..f3c5c6b18 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceTable.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/CrossReferenceTable.java @@ -1,12 +1,9 @@ package org.icepdf.core.pobjects.structure; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.structure.exceptions.CrossReferenceStateException; -import org.icepdf.core.pobjects.structure.exceptions.ObjectStateException; +import org.icepdf.core.pobjects.Dictionary; +import org.icepdf.core.pobjects.DictionaryEntries; +import org.icepdf.core.pobjects.Reference; import org.icepdf.core.util.Library; -import org.icepdf.core.util.parser.object.ObjectLoader; - -import java.io.IOException; /** * @@ -17,15 +14,6 @@ public CrossReferenceTable(Library library, DictionaryEntries dictionaryEntries, super(new Dictionary(library, dictionaryEntries), xrefStartPos); } - @Override - public PObject loadObject(ObjectLoader objectLoader, Reference reference, Name hint) - throws ObjectStateException, CrossReferenceStateException, IOException { - if (reference != null) { - return objectLoader.loadObject(this, reference, hint); - } - return null; - } - public void addEntry(CrossReferenceEntry crossReferenceEntry) { int generation; if (crossReferenceEntry instanceof CrossReferenceUsedEntry) { diff --git a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/Header.java b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/Header.java index 9df3feaaa..d91ae3e36 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/Header.java +++ b/core/core-awt/src/main/java/org/icepdf/core/pobjects/structure/Header.java @@ -41,7 +41,7 @@ public ByteBuffer parseHeader(ByteBuffer byteBuffer) { if (matchPosition == matchLength) { version = parseVersion(headerBuffer); } else { - version = 0; + version = 1.0; } // check for some bad bytes @@ -69,7 +69,7 @@ private static double parseVersion(ByteBuffer buffer) { } catch (NumberFormatException e) { // quite for now. } - return 0; + return 1.0; } } \ No newline at end of file diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/Library.java b/core/core-awt/src/main/java/org/icepdf/core/util/Library.java index e42c4db45..96fce6a5f 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/util/Library.java +++ b/core/core-awt/src/main/java/org/icepdf/core/util/Library.java @@ -29,6 +29,7 @@ import org.icepdf.core.pobjects.graphics.images.references.ImagePool; import org.icepdf.core.pobjects.security.SecurityManager; import org.icepdf.core.pobjects.structure.CrossReferenceRoot; +import org.icepdf.core.pobjects.structure.Header; import org.icepdf.core.pobjects.structure.Indexer; import org.icepdf.core.pobjects.structure.exceptions.CrossReferenceStateException; import org.icepdf.core.pobjects.structure.exceptions.ObjectStateException; @@ -57,8 +58,7 @@ */ public class Library { - private static final Logger logger = - Logger.getLogger(Library.class.toString()); + private static final Logger logger = Logger.getLogger(Library.class.toString()); protected static ThreadPoolExecutor commonThreadPool; protected static ThreadPoolExecutor imageThreadPool; @@ -95,7 +95,7 @@ public class Library { private final ConcurrentHashMap> lookupReference2ICCBased = new ConcurrentHashMap<>(256); - private double fileVersion = 1.0; + private Header fileHeader; private String fileOrigin; private ByteBuffer mappedFileByteBuffer; @@ -194,7 +194,7 @@ private Object getObject(Reference reference, Name hint) { return ((PObject) obj).getObject(); } else if (obj instanceof Reference) { Reference secondReference = (Reference) obj; - logger.log(Level.WARNING, () -> "Found a reference to a reference: " + secondReference); + logger.log(Level.WARNING, () -> "Found a reference to a reference: " + secondReference); return getObject(secondReference); } return obj; @@ -202,7 +202,7 @@ private Object getObject(Reference reference, Name hint) { private boolean isSoftReferenceAble(Object object) { if (object instanceof Dictionary) { - DictionaryEntries entries = ((Dictionary)object).getEntries(); + DictionaryEntries entries = ((Dictionary) object).getEntries(); Name type = getName(entries, Dictionary.TYPE_KEY); if (type != null) { return type.equals(Font.TYPE) || @@ -359,12 +359,12 @@ public Object getMappedFileByteBufferLock() { return mappedFileByteBufferLock; } - public double getFileVersion() { - return fileVersion; + public Header getFileHeader() { + return fileHeader; } - public void setFileVersion(double fileVersion) { - this.fileVersion = fileVersion; + public void setFileHeader(Header header) { + this.fileHeader = header; } /** @@ -692,6 +692,7 @@ public Rectangle2D.Float getRectangle(DictionaryEntries dictionaryEntries, Name /** * Checks the given values for floats and resolves and References. + * * @param values list of floats * @return list of floats */ @@ -711,8 +712,8 @@ public List getFloatList(List values) { private Float getFloatNumber(Object object) { if (object instanceof Number) { return ((Number) object).floatValue(); - } else if (object instanceof Reference) { - return ((Number)getObject((Reference) object)).floatValue(); + } else if (object instanceof Reference) { + return ((Number) getObject((Reference) object)).floatValue(); } else { return null; } diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/updater/FullUpdater.java b/core/core-awt/src/main/java/org/icepdf/core/util/updater/FullUpdater.java index 5a8cc410c..c5a6e88a7 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/util/updater/FullUpdater.java +++ b/core/core-awt/src/main/java/org/icepdf/core/util/updater/FullUpdater.java @@ -1,21 +1,21 @@ package org.icepdf.core.util.updater; -import org.icepdf.core.pobjects.Catalog; -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.PObject; -import org.icepdf.core.pobjects.StateManager; +import org.icepdf.core.io.CountingOutputStream; +import org.icepdf.core.pobjects.*; +import org.icepdf.core.pobjects.security.SecurityManager; import org.icepdf.core.pobjects.structure.CrossReferenceRoot; -import org.icepdf.core.pobjects.structure.Indexer; -import org.icepdf.core.pobjects.structure.exceptions.ObjectStateException; import org.icepdf.core.util.Library; -import org.icepdf.core.util.parser.object.Parser; +import org.icepdf.core.util.updater.writeables.BaseWriter; import java.io.IOException; import java.io.OutputStream; -import java.nio.ByteBuffer; +import java.util.List; public class FullUpdater { + private Library library; + private StateManager stateManager; + /** * Write a new document inserted and updating modified objects to the specified output stream. * @@ -28,33 +28,90 @@ public long writeDocument( Document document, OutputStream outputStream) throws IOException { Catalog catalog = document.getCatalog(); - Library library = catalog.getLibrary(); + library = catalog.getLibrary(); + stateManager = library.getStateManager(); CrossReferenceRoot crossReferenceRoot = library.getCrossReferenceRoot(); - StateManager stateManager = library.getStateManager(); + SecurityManager securityManager = library.getSecurityManager(); + CountingOutputStream output = new CountingOutputStream(outputStream); + + BaseWriter writer = new BaseWriter(crossReferenceRoot, securityManager, output, 0); + writer.initializeWriters(); Object mappedFileByteBufferLock = library.getMappedFileByteBufferLock(); - Indexer indexer = new Indexer(library); - Parser parser = new Parser(library); + synchronized (mappedFileByteBufferLock) { - try { - ByteBuffer mappedFileByteBuffer = library.getMappedFileByteBuffer(); - PObject next; - int offset = 0; - do { - next = parser.getPObject(mappedFileByteBuffer, offset); - offset = mappedFileByteBuffer.position(); - if (stateManager.contains(next.getReference())) { - StateManager.Change change = stateManager.getChange(next.getReference()); - System.out.println("found a change " + change.getType()); - } - System.out.println(offset); + // write header + writer.writeHeader(library.getFileHeader()); + + // use the document root/catalog to iterate over the object tree writing out each object. + // and keep track of each + writeDictionary(writer, catalog); + + writer.writeXRefTable(); + writer.writeFullTrailer(); + + } + + // todo pass + return writer.getBytesWritten(); + } + + private void writeDictionary(BaseWriter writer, Dictionary dictionary) throws IOException { + Reference dictionaryReference = dictionary.getPObjectReference(); + if (writer.hasNotWrittenReference(dictionaryReference)) { + StateManager.Change change = stateManager.getChange(dictionaryReference); + if (change != null) { + if (change.getType() == StateManager.Type.CHANGE) { + writer.writePObject(change.getPObject()); } - while (next != null); - } catch (ObjectStateException e) { - throw new RuntimeException(e); + } else { + writer.writePObject(new PObject(dictionary, dictionary.getPObjectReference())); } } + DictionaryEntries entries = dictionary.getEntries(); + findChildDictionaries(writer, entries); + } - return 0; + private void findChildDictionaries(BaseWriter writer, DictionaryEntries entries) throws IOException { + for (Name name : entries.keySet()) { + Object value = entries.get(name); + if (value instanceof Reference && writer.hasNotWrittenReference((Reference) value)) { + Object object = library.getObject(value); + StateManager.Change change = stateManager.getChange((Reference) value); + if (change != null) { + if (change.getType() == StateManager.Type.CHANGE) { + writer.writePObject(change.getPObject()); + } + } else { + writer.writePObject(new PObject(object, (Reference) value)); + } + if (object instanceof Dictionary) { + writeDictionary(writer, (Dictionary) object); + } else if (object instanceof DictionaryEntries) { + findChildDictionaries(writer, (DictionaryEntries) object); + } + } else if (value instanceof List) { + for (Object object : (List) value) { + if (object instanceof Reference && writer.hasNotWrittenReference((Reference) object)) { + Object objectReferenceValue = library.getObject(object); + StateManager.Change change = stateManager.getChange((Reference) object); + if (change != null) { + if (change.getType() == StateManager.Type.CHANGE) { + writer.writePObject(change.getPObject()); + } + } else { + writer.writePObject(new PObject(objectReferenceValue, (Reference) object)); + } + if (objectReferenceValue instanceof Dictionary) { + writeDictionary(writer, (Dictionary) objectReferenceValue); + } else if (objectReferenceValue instanceof DictionaryEntries) { + findChildDictionaries(writer, (DictionaryEntries) objectReferenceValue); + } + } + } + } else if (value instanceof DictionaryEntries) { + findChildDictionaries(writer, (DictionaryEntries) value); + } + } } } diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/updater/IncrementalUpdater.java b/core/core-awt/src/main/java/org/icepdf/core/util/updater/IncrementalUpdater.java index ed509d5ea..46a63e54f 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/util/updater/IncrementalUpdater.java +++ b/core/core-awt/src/main/java/org/icepdf/core/util/updater/IncrementalUpdater.java @@ -52,7 +52,7 @@ public long appendIncrementalUpdate( writer.writeCompressedXrefTable(); } else { writer.writeXRefTable(); - writer.writeTrailer(); + writer.writeIncrementalUpdateTrailer(); } output.close(); diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/BaseWriter.java b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/BaseWriter.java index 8fdf75264..ec22361ea 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/BaseWriter.java +++ b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/BaseWriter.java @@ -4,10 +4,12 @@ import org.icepdf.core.pobjects.*; import org.icepdf.core.pobjects.security.SecurityManager; import org.icepdf.core.pobjects.structure.CrossReferenceRoot; +import org.icepdf.core.pobjects.structure.Header; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; /** @@ -25,6 +27,7 @@ public class BaseWriter { protected static final byte[] BEGIN_OBJECT = "obj\r\n".getBytes(); protected static final byte[] END_OBJECT = "endobj\r\n".getBytes(); + private static HeaderWriter headerWriter; private static NameWriter nameWriter; private static DictionaryWriter dictionaryWriter; private static ReferenceWriter referenceWriter; @@ -43,10 +46,11 @@ public class BaseWriter { private SecurityManager securityManager; private CrossReferenceRoot crossReferenceRoot; private long startingPosition; - private List entries; + private ArrayList entries; + private HashMap entriesMap; private long xrefPosition; - public BaseWriter(){ + public BaseWriter() { } @@ -56,12 +60,14 @@ public BaseWriter(CrossReferenceRoot crossReferenceRoot, SecurityManager securit this.crossReferenceRoot = crossReferenceRoot; this.securityManager = securityManager; this.startingPosition = startingPosition; - entries = new ArrayList<>(256); + entries = new ArrayList<>(512); + entriesMap = new HashMap<>(512); } public void initializeWriters() { // reuse instances of primitive pdf types. streamWriter = new StreamWriter(); + headerWriter = new HeaderWriter(); nameWriter = new NameWriter(); dictionaryWriter = new DictionaryWriter(); referenceWriter = new ReferenceWriter(); @@ -75,12 +81,18 @@ public void initializeWriters() { compressedXrefTableWriter = new CompressedXrefTableWriter(); } + public boolean hasNotWrittenReference(Reference reference) { + return !entriesMap.containsKey(reference); + } + public long getBytesWritten() { return output.getCount(); } public void writePObject(PObject pobject) throws IOException { - entries.add(new Entry(pobject.getReference(), startingPosition + output.getCount())); + Entry entry = new Entry(pobject.getReference(), startingPosition + output.getCount()); + entries.add(entry); + entriesMap.put(pobject.getReference(), entry); if (pobject.getObject() instanceof Stream) { Stream stream = (Stream) pobject.getObject(); Reference reference = stream.getPObjectReference(); @@ -89,7 +101,6 @@ public void writePObject(PObject pobject) throws IOException { return; } streamWriter.write((Stream) pobject.getObject(), securityManager, output); - } else { pObjectWriter.write(pobject, output); } @@ -99,8 +110,12 @@ public void writeXRefTable() throws IOException { xrefPosition = xRefTableWriter.writeXRefTable(entries, startingPosition, output); } - public void writeTrailer() throws IOException { - trailerWriter.writeTrailer(crossReferenceRoot, xrefPosition, entries, output); + public void writeIncrementalUpdateTrailer() throws IOException { + trailerWriter.writeIncrementalUpdateTrailer(crossReferenceRoot, xrefPosition, entries, output); + } + + public void writeFullTrailer() throws IOException { + trailerWriter.writeFullTrailer(crossReferenceRoot, xrefPosition, entries, output); } public void writeCompressedXrefTable() throws IOException { @@ -111,6 +126,10 @@ public void writeNewLine() throws IOException { output.write(NEWLINE); } + public void writeHeader(Header header) throws IOException { + headerWriter.write(header, output); + } + protected void writeValue(Object val, CountingOutputStream output) throws IOException { if (val == null) { output.write(NULL); diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/HeaderWriter.java b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/HeaderWriter.java new file mode 100644 index 000000000..41ed6ddb4 --- /dev/null +++ b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/HeaderWriter.java @@ -0,0 +1,22 @@ +package org.icepdf.core.util.updater.writeables; + +import org.icepdf.core.io.CountingOutputStream; +import org.icepdf.core.pobjects.structure.Header; + +import java.io.IOException; + +public class HeaderWriter extends BaseWriter { + + private static final byte[] commentMarker = "%".getBytes(); + + private static final byte[] FOUR_BYTES = "âãÏÓ".getBytes(); + + public void write(Header header, CountingOutputStream output) throws IOException { + output.write(commentMarker); + writeReal(header.getVersion(), output); + output.write(NEWLINE); + output.write(commentMarker); + output.write(FOUR_BYTES); + output.write(NEWLINE); + } +} diff --git a/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/TrailerWriter.java b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/TrailerWriter.java index 251ab194e..b5ee791c6 100644 --- a/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/TrailerWriter.java +++ b/core/core-awt/src/main/java/org/icepdf/core/util/updater/writeables/TrailerWriter.java @@ -11,7 +11,7 @@ public class TrailerWriter extends BaseTableWriter { - public void writeTrailer(CrossReferenceRoot crossReferenceRoot, long xrefPosition, List entries, CountingOutputStream output) + public void writeIncrementalUpdateTrailer(CrossReferenceRoot crossReferenceRoot, long xrefPosition, List entries, CountingOutputStream output) throws IOException { PTrailer prevTrailer = crossReferenceRoot.getTrailerDictionary(); DictionaryEntries newTrailer = (DictionaryEntries) prevTrailer.getDictionary().clone(); @@ -29,4 +29,21 @@ public void writeTrailer(CrossReferenceRoot crossReferenceRoot, long xrefPositio this.writeLong(xrefPosition, output); output.write(COMMENT_EOF); } + + public void writeFullTrailer(CrossReferenceRoot crossReferenceRoot, long xrefPosition, List entries, CountingOutputStream output) + throws IOException { + PTrailer prevTrailer = crossReferenceRoot.getTrailerDictionary(); + DictionaryEntries newTrailer = (DictionaryEntries) prevTrailer.getDictionary().clone(); + this.setTrailerSize(newTrailer, prevTrailer, entries); + newTrailer.remove(PTrailer.XREF_STRM_KEY); + newTrailer.remove(PTrailer.PREV_KEY); + + // todo update the ID with something fun. + + output.write(TRAILER); + this.writeDictionary(new Dictionary(null, newTrailer), output); + output.write(STARTXREF); + this.writeLong(xrefPosition, output); + output.write(COMMENT_EOF); + } } diff --git a/core/core-awt/src/test/java/org/icepdf/core/util/updater/ObjectUpdateTests.java b/core/core-awt/src/test/java/org/icepdf/core/util/updater/ObjectUpdateTests.java index e687516a9..71e6e7037 100644 --- a/core/core-awt/src/test/java/org/icepdf/core/util/updater/ObjectUpdateTests.java +++ b/core/core-awt/src/test/java/org/icepdf/core/util/updater/ObjectUpdateTests.java @@ -4,11 +4,10 @@ import org.icepdf.core.exceptions.PDFSecurityException; import org.icepdf.core.pobjects.Document; import org.icepdf.core.pobjects.Page; -import org.icepdf.core.util.Library; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -25,16 +24,13 @@ public void testXrefTableFullUpdate() { Page page = document.getPageTree().getPage(0); document.removePage(page); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(200000); - document.saveToOutputStream(outputStream, WriteMode.FULL_UPDATE); + FileOutputStream fileOutputStream = new FileOutputStream("./src/test/out/ObjectUpdateTest.pdf"); + document.saveToOutputStream(fileOutputStream, WriteMode.FULL_UPDATE); // check file length - outputStream.flush(); - outputStream.size(); + fileOutputStream.close(); - // make sure the following object are no longer present in file - Library library = document.getCatalog().getLibrary(); - /// library.getObject(); + // open the output and check for the missing objcts } catch (PDFSecurityException e) {