You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ad...@apache.org on 2011/04/16 04:38:31 UTC

svn commit: r1092855 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: cos/ pdfparser/ pdfwriter/ pdmodel/ pdmodel/interactive/annotation/ pdmodel/interactive/digitalsignature/ pdmodel/interactive/form/

Author: adam
Date: Sat Apr 16 02:38:31 2011
New Revision: 1092855

URL: http://svn.apache.org/viewvc?rev=1092855&view=rev
Log:
PDFBOX-912: PDF signing interface and improvements

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/COSDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.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=1092855&r1=1092854&r2=1092855&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 Sat Apr 16 02:38:31 2011
@@ -207,7 +207,7 @@ public class COSArray extends COSBase im
      */
     public COSBase get( int index )
     {
-        return (COSBase)objects.get( index );
+        return objects.get( index );
     }
 
     /**
@@ -356,7 +356,7 @@ public class COSArray extends COSBase im
      */
     public COSBase remove( int i )
     {
-        return (COSBase)objects.remove( i );
+        return objects.remove( i );
     }
 
     /**
@@ -404,6 +404,7 @@ public class COSArray extends COSBase im
     /**
      * {@inheritDoc}
      */
+    @Override
     public String toString()
     {
         return "COSArray{" + objects + "}";
@@ -503,6 +504,7 @@ public class COSArray extends COSBase im
      * @return any object, depending on the visitor implementation, or null
      * @throws COSVisitorException If an error occurs while visiting this object.
      */
+    @Override
     public Object accept(ICOSVisitor visitor) throws COSVisitorException
     {
         return visitor.visitFromArray(this);

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=1092855&r1=1092854&r2=1092855&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 Sat Apr 16 02:38:31 2011
@@ -32,8 +32,14 @@ public abstract class COSBase implements
     /**
      * Constructor.
      */
+  
+    private boolean needToBeUpdate;
+    
+    private boolean direct;
+  
     public COSBase()
     {
+      needToBeUpdate = false;
     }
 
     /**
@@ -69,4 +75,36 @@ public abstract class COSBase implements
      * @throws COSVisitorException If an error occurs while visiting this object.
      */
     public abstract Object accept(ICOSVisitor visitor) throws COSVisitorException;
+    
+    public void setNeedToBeUpdate(boolean flag) 
+    {
+      needToBeUpdate = flag;
+    }
+    
+    /**
+     * If the state is set true, the dictionary will be written direct into the called object. 
+     * This means, no indirect object will be created.
+     * 
+     * @return the state
+     */
+    public boolean isDirect() 
+    {
+        return direct;
+    }
+    
+    /**
+     * Set the state true, if the dictionary should be written as a direct object and not indirect.
+     * 
+     * @param direct set it true, for writting direct object
+     */
+    public void setDirect(boolean direct)
+    {
+      this.direct = direct;
+    }
+    
+    public boolean isNeedToBeUpdate() 
+    {
+      return needToBeUpdate;
+    }
+
 }

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=1092855&r1=1092854&r2=1092855&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 Sat Apr 16 02:38:31 2011
@@ -31,6 +31,7 @@ import org.apache.pdfbox.io.RandomAccess
 import org.apache.pdfbox.io.RandomAccessFile;
 import org.apache.pdfbox.pdfparser.PDFObjectStreamParser;
 import org.apache.pdfbox.pdfparser.PDFXrefStreamParser;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.apache.pdfbox.persistence.util.COSObjectKey;
 
 /**
@@ -67,6 +68,16 @@ public class COSDocument extends COSBase
      * Document trailer dictionary.
      */
     private COSDictionary trailer;
+    
+    /**
+     * Document signature dictionary
+     */
+    private COSDictionary signDictionary = null;
+    
+    /**
+     * Some doc
+     */
+    private SignatureInterface signatureInterface;
 
     /**
      * This file will store the streams in order to conserve memory.
@@ -78,7 +89,9 @@ public class COSDocument extends COSBase
     private String headerString = "%PDF-1.4";
 
     private boolean warnMissingClose = true;
-
+    
+    private int startXref;
+    
     private boolean closed = false;
 
     /**
@@ -313,9 +326,13 @@ public class COSDocument extends COSBase
         return (COSDictionary)trailer.getDictionaryObject( COSName.ENCRYPT );
     }
 
+    public SignatureInterface getSignatureInterface() {
+        return signatureInterface;
+    }
+    
     /**
      * This will set the encryption dictionary, this should only be called when
-     * encypting the document.
+     * encrypting the document.
      *
      * @param encDictionary The encryption dictionary.
      */
@@ -324,6 +341,35 @@ public class COSDocument extends COSBase
         trailer.setItem( COSName.ENCRYPT, encDictionary );
     }
 
+    public COSDictionary getLastSignatureDictionary() throws IOException {
+      if (signDictionary == null)
+      {
+        COSObject documentCatalog = getCatalog();
+        if (documentCatalog != null)
+        {
+          COSDictionary acroForm = (COSDictionary)documentCatalog.getDictionaryObject(COSName.getPDFName("AcroForm"));
+          if (acroForm !=null)
+          {
+            COSArray fields = (COSArray)acroForm.getDictionaryObject("Fields");
+            for ( Object object : fields )
+            {
+              COSObject dict = (COSObject)object;
+              if(dict.getItem(COSName.getPDFName("FT")).equals(COSName.getPDFName("Sig")))
+              {
+                COSBase dictionaryObject = dict.getDictionaryObject(COSName.V);
+                
+                if (dictionaryObject != null) 
+                {
+                  signDictionary = (COSDictionary)dictionaryObject;
+                }
+              }
+            }
+          }
+        }
+      }
+      return signDictionary;
+    }
+    
     /**
      * This will get the document ID.
      *
@@ -343,6 +389,10 @@ public class COSDocument extends COSBase
     {
         getTrailer().setItem(COSName.ID, id);
     }
+    
+    public void setSignatureInterface(SignatureInterface signatureInterface) {
+      this.signatureInterface = signatureInterface;
+    }
 
     /**
      * This will get the document catalog.
@@ -401,6 +451,7 @@ public class COSDocument extends COSBase
      * @return any object, depending on the visitor implementation, or null
      * @throws COSVisitorException If an error occurs while visiting this object.
      */
+    @Override
     public Object accept(ICOSVisitor visitor) throws COSVisitorException
     {
         return visitor.visitFromDocument( this );
@@ -428,6 +479,7 @@ public class COSDocument extends COSBase
      * idea for the user to close the PDF document at the earliest possible to conserve resources.
      * @throws IOException if an error occurs while closing the temporary files
      */
+    @Override
     protected void finalize() throws IOException
     {
         if (!closed) {
@@ -505,7 +557,7 @@ public class COSDocument extends COSBase
         COSObject obj = null;
         if( key != null )
         {
-            obj = (COSObject) objectPool.get(key);
+            obj = objectPool.get(key);
         }
         if (obj == null)
         {
@@ -573,5 +625,25 @@ public class COSDocument extends COSBase
         }
         setTrailer( trailerDict );
     }
+    
+    /**
+     * This method set the startxref value of the document. This will only 
+     * be needed for incremental updates.
+     * 
+     * @param readInt
+     */
+    public void setStartXref(int startXref)
+    {
+      this.startXref = startXref;
+    }
 
+    /**
+     * Return the startXref Position of the parsed document. This will only be needed for incremental updates.
+     * 
+     * @return a int with the old position of the startxref
+     */
+    public int getStartXref()
+    {
+      return startXref;
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Sat Apr 16 02:38:31 2011
@@ -1115,6 +1115,56 @@ public final class COSName extends COSBa
      */
     public static final byte[] NAME_ESCAPE = new byte[] { 35  };  //The # character
 
+    /**
+     * A common COSName value.
+     */
+    public static final COSName SUBFILTER = new COSName("SubFilter");
+    /**
+     * A signature filter value.
+     */
+    public static final COSName ADOBE_PPKLITE = new COSName("Adobe.PPKLite");
+    /**
+     * A signature filter value.
+     */
+    public static final COSName ENTRUST_PPKEF = new COSName("Entrust.PPKEF");
+    /**
+     * A signature filter value.
+     */
+    public static final COSName CICI_SIGNIT = new COSName("CICI.SignIt");
+    /**
+     * A signature filter value.
+     */
+    public static final COSName VERISIGN_PPKVS = new COSName("VeriSign.PPKVS");
+    /**
+     * A signature subfilter value.
+     */
+    public static final COSName ADBE_X509_RSA_SHA1 = new COSName("adbe.x509.rsa_sha1");
+    /**
+     * A signature subfilter value.
+     */
+    public static final COSName ADBE_PKCS7_DETACHED = new COSName("adbe.pkcs7.detached");
+    /**
+     * A signature subfilter value.www
+     */
+    public static final COSName ADBE_PKCS7_SHA1 = new COSName("adbe.pkcs7.sha1");
+    /**
+     * A common COSName value.
+     */
+    public static final COSName LOCATION = new COSName("Location");
+    /**
+     * A common COSName value.
+     */
+    public static final COSName REASON = new COSName("Reason");
+    /**
+     * A common COSName value.
+     */
+    public static final COSName BYTERANGE = new COSName("ByteRange");
+    /**
+     * A common COSName value.
+     */
+    public static final COSName SIG = new COSName("Sig");
+
+    
     private String name;
     private int hashCode;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java Sat Apr 16 02:38:31 2011
@@ -21,9 +21,8 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
-import org.apache.pdfbox.persistence.util.COSHEXTable;
-
 import org.apache.pdfbox.exceptions.COSVisitorException;
+import org.apache.pdfbox.persistence.util.COSHEXTable;
 
 /**
  * This represents a string object in a PDF document.
@@ -83,6 +82,10 @@ public class COSString extends COSBase
      */
     private boolean forceLiteralForm = false;
 
+    /**
+     * Forces the string to be serialized in hex form but not literal form.
+     */
+    private boolean forceHexForm = false;
 
     /**
      * Constructor.
@@ -166,6 +169,18 @@ public class COSString extends COSBase
     }
 
     /**
+     * Forces the string to be written in hexadecimal form instead of literal form.
+     * 
+     * @param v if v is true the string will be written in hexadecimal form otherwise it will be written in literal if
+     *          necessary.
+     */
+
+    public void setForceHexForm(boolean v)
+    {
+      forceHexForm = v;
+    }
+    
+    /**
      * This will create a COS string from a string of hex characters.
      *
      * @param hex A hex string.
@@ -322,6 +337,7 @@ public class COSString extends COSBase
     /**
      * {@inheritDoc}
      */
+    @Override
     public String toString()
     {
         return "COSString{" + this.getString() + "}";
@@ -345,7 +361,7 @@ public class COSString extends COSBase
             //outside the ASCII range.
             outsideASCII = bytes[i] <0;
         }
-        if( !outsideASCII || forceLiteralForm )
+        if ((!outsideASCII || forceLiteralForm) && !forceHexForm)
         {
             output.write(STRING_OPEN);
             for( int i=0; i<length; i++ )
@@ -358,7 +374,7 @@ public class COSString extends COSBase
                     case '\\':
                     {
                         output.write(ESCAPE);
-                        output.write(b);
+                        output.write((byte)b);
                         break;
                     }
                     case 10: //LF
@@ -388,7 +404,7 @@ public class COSString extends COSBase
                     }
                     default:
                     {
-                        output.write( b );
+                        output.write( (byte)b );
                     }
                 }
             }
@@ -414,6 +430,7 @@ public class COSString extends COSBase
      * @return any object, depending on the visitor implementation, or null
      * @throws COSVisitorException If an error occurs while visiting this object.
      */
+    @Override
     public Object accept(ICOSVisitor visitor) throws COSVisitorException
     {
         return visitor.visitFromString( this );
@@ -422,6 +439,7 @@ public class COSString extends COSBase
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean equals(Object obj)
     {
         if (obj instanceof COSString)
@@ -435,6 +453,7 @@ public class COSString extends COSBase
     /**
      * {@inheritDoc}
      */
+    @Override
     public int hashCode()
     {
         return getString().hashCode();

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFParser.java Sat Apr 16 02:38:31 2011
@@ -218,7 +218,7 @@ public class PDFParser extends BaseParse
                 if( !wasLastParsedObjectEOF )
                 {
                     throw e;
-                } 
+                }
             }
         }
         catch( Throwable t )
@@ -647,9 +647,9 @@ public class PDFParser extends BaseParse
         }
         skipSpaces();
         /* This integer is the byte offset of the first object referenced by the xref or xref stream
-         * Not needed for PDFbox
+         * Needed for the incremental update (PREV)
          */
-        readInt();
+        getDocument().setStartXref(readInt());
         return true;
     }
 
@@ -806,6 +806,7 @@ public class PDFParser extends BaseParse
             this.objectKey = key;
             this.object = pdfObject;
         }
+        @Override
         public String toString()
         {
             return "Object(" + offset + ", " + objectKey + ")";

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSStandardOutputStream.java Sat Apr 16 02:38:31 2011
@@ -18,9 +18,14 @@ package org.apache.pdfbox.pdfwriter;
 
 
 
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.FilterOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.channels.FileChannel;
 
 import org.apache.pdfbox.util.StringUtil;
 
@@ -53,7 +58,10 @@ public class COSStandardOutputStream ext
     private long pos = 0;
     // flag to prevent generating two newlines in sequence
     private boolean onNewLine = false;
-
+    private FileChannel fileChannel = null;
+    private FileDescriptor fileDescriptor = null;
+    private long mark = -1;
+    
     /**
      * COSOutputStream constructor comment.
      *
@@ -62,7 +70,17 @@ public class COSStandardOutputStream ext
     public COSStandardOutputStream(OutputStream out)
     {
         super(out);
+        if(out instanceof FileOutputStream) {
+            try {
+                fileChannel = ((FileOutputStream)out).getChannel();
+                fileDescriptor = ((FileOutputStream)out).getFD();
+                pos = fileChannel.position();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
     }
+    
     /**
      * This will get the current position in the stream.
      *
@@ -72,8 +90,24 @@ public class COSStandardOutputStream ext
     {
         return pos;
     }
+    
     /**
-     * This will tell if we are on a newling.
+     * This will get the current position in the stream.
+     *
+     * @return The current position in the stream.
+     * @throws IOException 
+     */
+    public void setPos(long pos) throws IOException
+    {
+        if(fileChannel!=null) {
+            checkPos();
+            this.pos=pos;
+            fileChannel.position(pos);
+        }
+    }
+    
+    /**
+     * This will tell if we are on a newline.
      *
      * @return true If we are on a newline.
      */
@@ -100,8 +134,10 @@ public class COSStandardOutputStream ext
      *
      * @throws IOException If the underlying stream throws an exception.
      */
+    @Override
     public void write(byte[] b, int off, int len) throws IOException
     {
+        checkPos();
         setOnNewLine(false);
         out.write(b, off, len);
         pos += len;
@@ -114,13 +150,15 @@ public class COSStandardOutputStream ext
      *
      * @throws IOException If there is an error writing to the underlying stream.
      */
+    @Override
     public void write(int b) throws IOException
     {
+        checkPos();
         setOnNewLine(false);
         out.write(b);
         pos++;
     }
-
+    
     /**
      * This will write a CRLF to the stream.
      *
@@ -129,7 +167,6 @@ public class COSStandardOutputStream ext
     public void writeCRLF() throws IOException
     {
         write(CRLF);
-        // setOnNewLine(true);
     }
 
     /**
@@ -154,6 +191,34 @@ public class COSStandardOutputStream ext
     public void writeLF() throws IOException
     {
         write(LF);
-        // setOnNewLine(true);
+    }
+    
+    public void mark() throws IOException 
+    {
+        checkPos();
+        mark = getPos();
+    }
+    
+    public void reset() throws IOException 
+    {
+        if(mark<0)
+            return;
+        setPos(mark);
+    }
+    
+    private void checkPos() throws IOException 
+    {
+        if(fileChannel.position() != getPos())
+            throw new IOException("OutputStream has an invalid position");
+    }
+
+    public byte[] getFileInBytes(int[] byteRange) throws IOException 
+    {
+        return null;
+    }
+    
+    public InputStream getFilterInputStream(int[] byteRange) 
+    {
+        return new COSFilterInputStream(new FileInputStream(fileDescriptor), byteRange);
     }
 }

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=1092855&r1=1092854&r2=1092855&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 Sat Apr 16 02:38:31 2011
@@ -16,6 +16,9 @@
  */
 package org.apache.pdfbox.pdfwriter;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -24,11 +27,13 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -42,14 +47,17 @@ import org.apache.pdfbox.cos.COSFloat;
 import org.apache.pdfbox.cos.COSInteger;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNull;
+import org.apache.pdfbox.cos.COSNumber;
 import org.apache.pdfbox.cos.COSObject;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.cos.COSString;
 import org.apache.pdfbox.cos.ICOSVisitor;
 import org.apache.pdfbox.exceptions.COSVisitorException;
 import org.apache.pdfbox.exceptions.CryptographyException;
+import org.apache.pdfbox.exceptions.SignatureException;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.encryption.SecurityHandler;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.apache.pdfbox.persistence.util.COSObjectKey;
 import org.apache.pdfbox.util.StringUtil;
 
@@ -156,6 +164,7 @@ public class COSWriter implements ICOSVi
 
     // the stream where we create the pdf output
     private OutputStream output;
+
     // the stream used to write standard cos data
     private COSStandardOutputStream standardOutput;
 
@@ -170,13 +179,14 @@ public class COSWriter implements ICOSVi
     //A hashtable is used on purpose over a hashmap
     //so that null entries will not get added.
     private Map<COSBase,COSObjectKey> objectKeys = new Hashtable<COSBase,COSObjectKey>();
+    private Map<COSObjectKey,COSBase> keyObject = new Hashtable<COSObjectKey,COSBase>();
 
     // the list of x ref entries to be made so far
-    private LinkedList xRefEntries = new LinkedList();
+    private List<COSWriterXRefEntry> xRefEntries = new ArrayList<COSWriterXRefEntry>();
+    private HashSet<COSBase> objectsToWriteSet = new HashSet<COSBase>();
 
     //A list of objects to write.
     private LinkedList<COSBase> objectsToWrite = new LinkedList<COSBase>();
-    private HashSet<COSBase> objectsToWriteSet = new HashSet<COSBase>();
 
     //a list of objects already written
     private Set<COSBase> writtenObjects = new HashSet<COSBase>();
@@ -193,6 +203,16 @@ public class COSWriter implements ICOSVi
     private PDDocument document = null;
 
     private boolean willEncrypt = false;
+    
+    private boolean incrementalUpdate = false;
+    
+    private boolean reachedSignature = false;
+    
+    private int[] signaturePosition = new int[2];
+    
+    private int[] byterangePosition = new int[2];
+    
+    private FileInputStream in;
 
     /**
      * COSWriter constructor comment.
@@ -203,10 +223,57 @@ public class COSWriter implements ICOSVi
     {
         super();
         setOutput(os);
-        setStandardOutput(new COSStandardOutputStream(getOutput()));
+        setStandardOutput(new COSStandardOutputStream(output));
         formatDecimal.setMaximumFractionDigits( 10 );
         formatDecimal.setGroupingUsed( false );
     }
+    
+    /**
+     * COSWriter constructor for incremental updates. 
+     *
+     * @param os The wrapped output stream.
+     */
+    public COSWriter(OutputStream os, FileInputStream is)
+    {
+      this(os);
+      in = is;
+      incrementalUpdate = true;
+    }
+
+    protected void prepareIncrement(PDDocument doc)
+    {
+      try
+      {
+        if (doc != null)
+        {
+          COSDocument cosDoc = doc.getDocument();
+          
+          Map<COSObjectKey, Integer> xrefTable = cosDoc.getXrefTable();
+          Set<COSObjectKey> keySet = xrefTable.keySet();
+          long highestNumber=0;
+          for ( COSObjectKey cosObjectKey : keySet ) {
+            COSBase object = cosDoc.getObjectFromPool(cosObjectKey).getObject();
+            if (object != null && cosObjectKey!= null && !(object instanceof COSNumber))
+            {
+            objectKeys.put(object, cosObjectKey);
+            keyObject.put(cosObjectKey,object);
+            }
+            
+            long num = cosObjectKey.getNumber();
+            if (num > highestNumber)
+              highestNumber=num;
+          }
+          setNumber(highestNumber);
+          // xrefTable.clear();
+
+        }
+      }
+      catch (IOException e)
+      {
+        e.printStackTrace();
+      }
+    }
+    
     /**
      * add an entry in the x ref table for later dump.
      *
@@ -249,7 +316,7 @@ public class COSWriter implements ICOSVi
      *
      * @return A map of all object keys.
      */
-    public java.util.Map<COSBase,COSObjectKey> getObjectKeys()
+    public Map<COSBase,COSObjectKey> getObjectKeys()
     {
         return objectKeys;
     }
@@ -288,7 +355,7 @@ public class COSWriter implements ICOSVi
      *
      * @return All available xref entries.
      */
-    protected java.util.List getXRefEntries()
+    protected List<COSWriterXRefEntry> getXRefEntries()
     {
         return xRefEntries;
     }
@@ -347,15 +414,14 @@ public class COSWriter implements ICOSVi
         COSDictionary root = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT );
         COSDictionary info = (COSDictionary)trailer.getDictionaryObject( COSName.INFO );
         COSDictionary encrypt = (COSDictionary)trailer.getDictionaryObject( COSName.ENCRYPT );
-        if( root != null )
-        {
-            addObjectToWrite( root );
-        }
-        if( info != null )
-        {
-            addObjectToWrite( info );
-        }
-
+          if( root != null )
+          {
+              addObjectToWrite( root );
+          }
+          if( info != null )
+          {
+              addObjectToWrite( info );
+          }
 
         while( objectsToWrite.size() > 0 )
         {
@@ -378,7 +444,6 @@ public class COSWriter implements ICOSVi
             objectsToWriteSet.remove(nextObject);
             doWriteObject( nextObject );
         }
-
     }
 
     private void addObjectToWrite( COSBase object )
@@ -393,6 +458,21 @@ public class COSWriter implements ICOSVi
             !objectsToWriteSet.contains( object ) &&
             !actualsAdded.contains( actual ) )
         {
+            COSBase cosBase=null;
+            COSObjectKey cosObjectKey = null;
+            if(actual != null)
+                cosObjectKey= objectKeys.get(actual);
+          
+            if(cosObjectKey!=null)
+                cosBase = keyObject.get(cosObjectKey);
+          
+            if(actual != null && objectKeys.containsKey(actual) &&
+                    !object.isNeedToBeUpdate() && (cosBase!= null &&
+                    !cosBase.isNeedToBeUpdate()))
+            {
+                return;
+            }
+          
             objectsToWrite.add( object );
             objectsToWriteSet.add( object );
             if( actual != null )
@@ -414,6 +494,15 @@ public class COSWriter implements ICOSVi
         try
         {
             writtenObjects.add( obj );
+            if(obj instanceof COSDictionary) 
+            {
+                COSDictionary dict = (COSDictionary)obj;
+                COSName item = (COSName)dict.getItem(COSName.TYPE);
+                if(COSName.SIG.equals(item)) {
+                    reachedSignature = true;
+                }
+            }
+            
             // find the physical reference
             currentObjectKey = getObjectKey( obj );
             // add a x ref entry
@@ -469,9 +558,14 @@ public class COSWriter implements ICOSVi
         COSDictionary trailer = doc.getTrailer();
         //sort xref, needed only if object keys not regenerated
         Collections.sort(getXRefEntries());
-        COSWriterXRefEntry lastEntry = (COSWriterXRefEntry)getXRefEntries().get( getXRefEntries().size()-1);
+        COSWriterXRefEntry lastEntry = getXRefEntries().get( getXRefEntries().size()-1);
         trailer.setInt(COSName.SIZE, (int)lastEntry.getKey().getNumber()+1);
-        trailer.removeItem( COSName.PREV );
+        // Only need to stay, if an incremental update will be performed
+        if (!incrementalUpdate)
+          trailer.removeItem( COSName.PREV );
+        // Remove a checksum if present
+        trailer.removeItem( COSName.getPDFName("DocChecksum") );
+        
         /**
         COSObject catalog = doc.getCatalog();
         if (catalog != null)
@@ -486,6 +580,7 @@ public class COSWriter implements ICOSVi
         getStandardOutput().write(String.valueOf(getStartxref()).getBytes("ISO-8859-1"));
         getStandardOutput().writeEOL();
         getStandardOutput().write(EOF);
+        getStandardOutput().writeEOL();
     }
 
     /**
@@ -501,12 +596,9 @@ public class COSWriter implements ICOSVi
      */
     protected void doWriteXRef(COSDocument doc) throws IOException
     {
-        String offset;
-        String generation;
-
         // sort xref, needed only if object keys not regenerated
         Collections.sort(getXRefEntries());
-        COSWriterXRefEntry lastEntry = (COSWriterXRefEntry)getXRefEntries().get( getXRefEntries().size()-1 );
+        COSWriterXRefEntry lastEntry = getXRefEntries().get( getXRefEntries().size()-1 );
 
         // remember the position where x ref is written
         setStartxref(getStandardOutput().getPos());
@@ -515,48 +607,175 @@ public class COSWriter implements ICOSVi
         getStandardOutput().writeEOL();
         // write start object number and object count for this x ref section
         // we assume starting from scratch
-        getStandardOutput().write(String.valueOf(0).getBytes("ISO-8859-1"));
+        writeXrefRange(0, lastEntry.getKey().getNumber() + 1);
+        // write initial start object with ref to first deleted object and magic generation number
+        writeXrefEntry(COSWriterXRefEntry.getNullEntry());
+        // write entry for every object
+        long lastObjectNumber = 0;
+        for (Iterator<COSWriterXRefEntry> i = getXRefEntries().iterator(); i.hasNext();)
+        {
+            COSWriterXRefEntry entry = i.next();
+            while( lastObjectNumber<entry.getKey().getNumber()-1 )
+            {
+              writeXrefEntry(COSWriterXRefEntry.getNullEntry());
+            }
+            lastObjectNumber = entry.getKey().getNumber();
+            writeXrefEntry(entry);
+        }
+    }
+
+    protected void doWriteXRefInc(COSDocument doc) throws IOException
+    {
+        COSDictionary trailer = doc.getTrailer();
+        trailer.setLong(COSName.PREV, doc.getStartXref());
+        addXRefEntry(COSWriterXRefEntry.getNullEntry());
+
+        // sort xref, needed only if object keys not regenerated
+        Collections.sort(getXRefEntries());
+      
+        // remember the position where x ref was written
+        setStartxref(getStandardOutput().getPos());
+
+        getStandardOutput().write(XREF);
+        getStandardOutput().writeEOL();
+        // write start object number and object count for this x ref section
+        // we assume starting from scratch
+
+        Integer[] xRefRanges = getXRefRanges(getXRefEntries());
+        int xRefLength = xRefRanges.length;
+        int x = 0;
+        int j = 0;
+        while(x < xRefLength && (xRefLength % 2) == 0)
+        {
+            writeXrefRange(xRefRanges[x], xRefRanges[x + 1]);
+
+            for(int i = 0 ; i < xRefRanges[x + 1] ; ++i)
+            {
+                writeXrefEntry(xRefEntries.get(j++));
+            }
+            x += 2;
+        }
+    }
+
+    protected void doWriteSignature(COSDocument doc) throws IOException, SignatureException
+    {
+        // need to calculate the ByteRange
+        if (signaturePosition[0]>0 && byterangePosition[1] > 0)
+        {
+            int left = (int)getStandardOutput().getPos()-signaturePosition[1];
+            String newByteRange = "0 "+signaturePosition[0]+" "+signaturePosition[1]+" "+left+"]";
+            int leftByterange = byterangePosition[1]-byterangePosition[0]-newByteRange.length();
+            if(leftByterange<0)
+                throw new IOException("Can't write new ByteRange, not enough space");
+            getStandardOutput().setPos(byterangePosition[0]);
+            getStandardOutput().write(newByteRange.getBytes());
+            for(int i=0;i<leftByterange;++i)
+            {
+                getStandardOutput().write(0x20);
+            }
+        
+            getStandardOutput().setPos(0);
+            // Begin - extracting document
+            InputStream filterInputStream = new COSFilterInputStream(in, new int[] {0,signaturePosition[0],signaturePosition[1],left});
+            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+            try {
+                byte[] buffer = new byte[1024];
+                int c;
+                while((c = filterInputStream.read(buffer)) != -1)
+                    bytes.write(buffer, 0, c);
+            } finally {
+                if(filterInputStream !=null)
+                    filterInputStream.close();
+            }
+
+            byte[] pdfContent = bytes.toByteArray();
+            // End - extracting document
+        
+            SignatureInterface signatureInterface = doc.getSignatureInterface();
+            byte[] sign = signatureInterface.sign(new ByteArrayInputStream(pdfContent));
+            String signature = new COSString(sign).getHexString();
+            int leftSignaturerange = signaturePosition[1]-signaturePosition[0]-signature.length();
+            if(leftSignaturerange<0)
+                throw new IOException("Can't write signature, not enough space");
+            getStandardOutput().setPos(signaturePosition[0]+1);
+            getStandardOutput().write(signature.getBytes());
+        }
+    }
+    
+    protected void writeXrefRange(long x, long y) throws IOException
+    {
+        getStandardOutput().write(String.valueOf(x).getBytes());
         getStandardOutput().write(SPACE);
-        getStandardOutput().write(String.valueOf(lastEntry.getKey().getNumber() + 1).getBytes("ISO-8859-1"));
+        getStandardOutput().write(String.valueOf(y).getBytes());
         getStandardOutput().writeEOL();
-        // write initial start object with ref to first deleted object and magic generation number
-        offset = formatXrefOffset.format(0);
-        generation = formatXrefGeneration.format(65535);
+    }
+
+    protected void writeXrefEntry(COSWriterXRefEntry entry) throws IOException
+    {
+        String offset = formatXrefOffset.format(entry.getOffset());
+        String generation = formatXrefGeneration.format(entry.getKey().getGeneration());
         getStandardOutput().write(offset.getBytes("ISO-8859-1"));
         getStandardOutput().write(SPACE);
         getStandardOutput().write(generation.getBytes("ISO-8859-1"));
         getStandardOutput().write(SPACE);
-        getStandardOutput().write(XREF_FREE);
+        getStandardOutput().write(entry.isFree() ? XREF_FREE : XREF_USED);
         getStandardOutput().writeCRLF();
-        // write entry for every object
-        long lastObjectNumber = 0;
-        for (Iterator i = getXRefEntries().iterator(); i.hasNext();)
+    }
+
+    /**
+     * check the xref entries and write out the ranges.  The format of the
+     * returned array is exactly the same as the pdf specification.  See section
+     * 7.5.4 of ISO32000-1:2008, example 1 (page 40) for reference.
+     * <p>
+     * example: 0 1 2 5 6 7 8 10
+     * <p>
+     * will create a array with follow ranges
+     * <p>
+     * 0 3 5 4 10 1
+     * <p>
+     * this mean that the element 0 is followed by two other related numbers 
+     * that represent a cluster of the size 3. 5 is follow by three other
+     * related numbers and create a cluster of size 4. etc.
+     * 
+     * @param xRefEntries list with the xRef entries that was written
+     * @return a integer array with the ranges
+     */
+    protected Integer[] getXRefRanges(List<COSWriterXRefEntry> xRefEntries)
+    {
+        int nr = 0;
+        int last = -2;
+        int count = 1;
+
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        for( Object object : xRefEntries )
         {
-            COSWriterXRefEntry entry = (COSWriterXRefEntry) i.next();
-            while( lastObjectNumber<entry.getKey().getNumber()-1 )
+            nr = (int)((COSWriterXRefEntry)object).getKey().getNumber();
+            if (nr == last + 1)
             {
-                offset = formatXrefOffset.format(0);
-                generation = formatXrefGeneration.format(65535);
-                getStandardOutput().write(offset.getBytes("ISO-8859-1"));
-                getStandardOutput().write(SPACE);
-                getStandardOutput().write(generation.getBytes("ISO-8859-1"));
-                getStandardOutput().write(SPACE);
-                getStandardOutput().write(XREF_FREE);
-                getStandardOutput().writeCRLF();
-                lastObjectNumber++;
+                ++count;
+                last = nr;
+            }
+            else if (last == -2)
+            {
+                last = nr;
+            }
+            else
+            {
+                list.add(last - count + 1);
+                list.add(count);
+                last = nr;
+                count = 1;
             }
-            lastObjectNumber = entry.getKey().getNumber();
-            offset = formatXrefOffset.format(entry.getOffset());
-            generation = formatXrefGeneration.format(entry.getKey().getGeneration());
-            getStandardOutput().write(offset.getBytes("ISO-8859-1"));
-            getStandardOutput().write(SPACE);
-            getStandardOutput().write(generation.getBytes("ISO-8859-1"));
-            getStandardOutput().write(SPACE);
-            getStandardOutput().write(entry.isFree() ? XREF_FREE : XREF_USED);
-            getStandardOutput().writeCRLF();
         }
+        // If no new entry is found, we need to write out the last result
+        if(xRefEntries.size() > 0)
+        {
+            list.add(last - count + 1);
+            list.add(count);
+        }
+        return list.toArray(new Integer[list.size()]);
     }
-
+    
     /**
      * This will get the object key for the object.
      *
@@ -574,11 +793,11 @@ public class COSWriter implements ICOSVi
         COSObjectKey key = null;
         if( actual != null )
         {
-            key = (COSObjectKey)objectKeys.get(actual);
+            key = objectKeys.get(actual);
         }
         if( key == null )
         {
-            key = (COSObjectKey)objectKeys.get(obj);
+            key = objectKeys.get(obj);
         }
         if (key == null)
         {
@@ -712,8 +931,31 @@ public class COSWriter implements ICOSVi
                     getStandardOutput().write(SPACE);
                     if( value instanceof COSDictionary )
                     {
-                        addObjectToWrite( value );
-                        writeReference( value );
+                        COSDictionary dict = (COSDictionary)value;
+                        
+                        // write all XObjects as direct objects, this will save some size
+                        COSBase item = dict.getItem(COSName.XOBJECT);
+                        if(item!=null)
+                        {
+                            item.setDirect(true);
+                        }
+                        item = dict.getItem(COSName.RESOURCES);
+                        if(item!=null)
+                        {
+                            item.setDirect(true);
+                        }
+
+                        if(dict.isDirect()) 
+                        {
+                            // If the object should be written direct, we need
+                            // to pass the dictionary to the visitor again.
+                            visitFromDictionary(dict);
+                        }
+                        else 
+                        {
+                            addObjectToWrite( dict );
+                            writeReference( dict );
+                        }
                     }
                     else if( value instanceof COSObject )
                     {
@@ -730,7 +972,27 @@ public class COSWriter implements ICOSVi
                     }
                     else
                     {
-                        value.accept(this);
+                        // If we reach the pdf signature, we need to determinate the position of the
+                        // content and byterange
+                        if(reachedSignature && COSName.CONTENTS.equals(entry.getKey()))
+                        {
+                            signaturePosition = new int[2];
+                            signaturePosition[0] = (int)getStandardOutput().getPos();
+                            value.accept(this);
+                            signaturePosition[1] = (int)getStandardOutput().getPos();
+                        }
+                        else if(reachedSignature && COSName.BYTERANGE.equals(entry.getKey()))
+                        {
+                            byterangePosition = new int[2];
+                            byterangePosition[0] = (int)getStandardOutput().getPos()+1;
+                            value.accept(this);
+                            byterangePosition[1] = (int)getStandardOutput().getPos()-1;
+                            reachedSignature = false;
+                        }
+                        else
+                        {
+                            value.accept(this);
+                        }
                     }
                     getStandardOutput().writeEOL();
 
@@ -766,16 +1028,26 @@ public class COSWriter implements ICOSVi
     {
         try
         {
-            doWriteHeader(doc);
+            if(!incrementalUpdate)
+                doWriteHeader(doc);
             doWriteBody(doc);
-            doWriteXRef(doc);
+            if(incrementalUpdate)
+                doWriteXRefInc(doc);
+            else
+                doWriteXRef(doc);
             doWriteTrailer(doc);
+            doWriteSignature(doc);
+            
             return null;
         }
         catch (IOException e)
         {
             throw new COSVisitorException(e);
         }
+        catch (SignatureException e)
+        {
+            throw new COSVisitorException(e);
+        }
     }
 
     /**
@@ -995,6 +1267,8 @@ public class COSWriter implements ICOSVi
     public void write(PDDocument doc) throws COSVisitorException
     {
         document = doc;
+        if(incrementalUpdate)
+            prepareIncrement(doc);
         
         // if the document says we should remove encryption, then we shouldn't encrypt
         if(doc.isAllSecurityToBeRemoved())
@@ -1034,7 +1308,7 @@ public class COSWriter implements ICOSVi
         COSDocument cosDoc = document.getDocument();
         COSDictionary trailer = cosDoc.getTrailer();
         COSArray idArray = (COSArray)trailer.getDictionaryObject( COSName.ID );
-        if( idArray == null )
+        if( idArray == null || incrementalUpdate)
         {
             try
             {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriterXRefEntry.java Sat Apr 16 02:38:31 2011
@@ -27,29 +27,45 @@ import org.apache.pdfbox.cos.COSBase;
  * @author Michael Traut
  * @version $Revision: 1.7 $
  */
-public class COSWriterXRefEntry implements Comparable
+public class COSWriterXRefEntry implements Comparable<COSWriterXRefEntry>
 {
     private long offset;
     private COSBase object;
     private COSObjectKey key;
     private boolean free = false;
-
+    private static COSWriterXRefEntry nullEntry;
 
 
     /**
      * {@inheritDoc}
      */
-    public int compareTo(Object obj)
+    public int compareTo(COSWriterXRefEntry obj)
     {
         if (obj instanceof COSWriterXRefEntry)
         {
-            return (int)(getKey().getNumber() - ((COSWriterXRefEntry)obj).getKey().getNumber());
+            return (int)(getKey().getNumber() - obj.getKey().getNumber());
         }
         else
         {
             return -1;
         }
     }
+    
+    /**
+     * This will return a null entry: 0000000000 65535 f
+     * 
+     * @return null COSWriterXRefEntry
+     */
+    public static COSWriterXRefEntry getNullEntry()
+    {
+      if (nullEntry == null)
+      {
+        nullEntry = new COSWriterXRefEntry(0, null, new COSObjectKey(0, 65535));
+        nullEntry.setFree(true);
+      }
+      return nullEntry;
+    }
+    
     /**
      * This will get the Object key.
      *

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=1092855&r1=1092854&r2=1092855&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 Sat Apr 16 02:38:31 2011
@@ -29,6 +29,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -44,10 +45,12 @@ import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.exceptions.COSVisitorException;
 import org.apache.pdfbox.exceptions.CryptographyException;
 import org.apache.pdfbox.exceptions.InvalidPasswordException;
+import org.apache.pdfbox.exceptions.SignatureException;
 import org.apache.pdfbox.io.RandomAccess;
 import org.apache.pdfbox.pdfparser.PDFParser;
 import org.apache.pdfbox.pdfwriter.COSWriter;
 import org.apache.pdfbox.pdmodel.common.COSArrayList;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
 import org.apache.pdfbox.pdmodel.encryption.BadSecurityHandlerException;
@@ -58,6 +61,13 @@ import org.apache.pdfbox.pdmodel.encrypt
 import org.apache.pdfbox.pdmodel.encryption.SecurityHandlersManager;
 import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
 import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
 
 /**
  * This is the in-memory representation of the PDF document.  You need to call
@@ -72,6 +82,8 @@ import org.apache.pdfbox.pdmodel.encrypt
  */
 public class PDDocument implements Pageable
 {
+    private static final String COSDictionary = null;
+
     private COSDocument document;
 
     // NOTE BGUILLON: this property must be removed because it is
@@ -86,7 +98,7 @@ public class PDDocument implements Pagea
     //cached values
     private PDDocumentInformation documentInformation;
     private PDDocumentCatalog documentCatalog;
-
+    
     //The encParameters will be cached here.  When the document is decrypted then
     //the COSDocument will not have an "Encrypt" dictionary anymore and this object
     //must be used.
@@ -110,14 +122,14 @@ public class PDDocument implements Pagea
      * the page number for bookmarks (or page numbers for anything else for
      * which you have an object id for that matter). 
      */
-    private Map pageMap = null;
+    private Map<String, Integer> pageMap = null;
     
     /**
      * This will hold a flag which tells us if we should remove all security
      * from this documents
      */
     private boolean allSecurityToBeRemoved = false;
-
+    
     /**
      * Constructor, creates a new PDF Document with no pages.  You need to add
      * at least one page for the document to be valid.
@@ -149,12 +161,13 @@ public class PDDocument implements Pagea
 
     private void generatePageMap() 
     {
-        pageMap = new HashMap();
+        pageMap = new HashMap<String,Integer>();
         // these page nodes could be references to pages, 
         // or references to arrays which have references to pages
         // or references to arrays which have references to arrays which have references to pages
         // or ... (I think you get the idea...)
-        processListOfPageReferences(getDocumentCatalog().getPages().getKids());
+				processListOfPageReferences(getDocumentCatalog().getPages().getKids());
+
     }
     
     private void processListOfPageReferences(List<Object> pageNodes)
@@ -164,7 +177,7 @@ public class PDDocument implements Pagea
             Object pageOrArray = pageNodes.get(i);
             if(pageOrArray instanceof PDPage)
             {
-                COSArray pageArray = ((COSArrayList)(((PDPage)pageOrArray).getParent()).getKids()).toList();
+                List pageArray = ((((PDPage)pageOrArray).getParent()).getKids());
                 parseCatalogObject((COSObject)pageArray.get(i));
             }
             else if(pageOrArray instanceof PDPageNode)
@@ -240,7 +253,7 @@ public class PDDocument implements Pagea
      * 
      * @return the pageMap
      */
-    public final Map getPageMap() 
+    public final Map<String,Integer> getPageMap() 
     {
         if (pageMap == null)
         {
@@ -264,6 +277,175 @@ public class PDDocument implements Pagea
         rootPages.updateCount();
     }
 
+    public void addSignature(PDSignature sigObject, SignatureInterface signatureInterface) throws IOException, SignatureException
+    {
+      SignatureOptions defaultOptions = new SignatureOptions();
+      defaultOptions.setPage(1);
+      
+      addSignature(sigObject, signatureInterface,defaultOptions);
+    }
+    
+    /**
+     * This will add a signature to the document. 
+     *
+     * @param sigObject is the PDSignature model
+     * @param signatureInterface is a interface which provides signing capabilities
+     * @param options 
+     * @throws IOException if there is an error creating required fields
+     */
+    public void addSignature(PDSignature sigObject, SignatureInterface signatureInterface, SignatureOptions options) throws IOException, SignatureException
+    {
+      // Content reservieren
+      // Um auch grosse Zertifikatsketten unterbringen zu koennen, 
+      // wird ein sehr grosser Bereich reserviert
+      sigObject.setContents(new byte[0x2500 * 2 + 2]);
+
+      // ByteRange reservieren
+      sigObject.setByteRange(new int[] {0,1000000000,1000000000,1000000000});
+      
+      getDocument().setSignatureInterface(signatureInterface);
+      
+      // #########################################
+      // # SignatureForm fuer Signatur erstellen #
+      // # und mit an das Dokument haengen.      #
+      // #########################################
+      
+      // Erste Seite besorgen
+      PDDocumentCatalog root = getDocumentCatalog();
+      PDPageNode rootPages = root.getPages();
+      List<PDPage> kids = new ArrayList<PDPage>();
+      rootPages.getAllKids(kids);
+      
+      int size = (int)rootPages.getCount();
+      PDPage page = null;
+      if (size == 0)
+        throw new SignatureException(SignatureException.INVALID_PAGE_FOR_SIGNATURE, "The PDF file has no pages");
+      if (options.getPage()>size)
+        page = kids.get(size-1);
+      else if(options.getPage()<=0)
+        page = kids.get(0);
+      else
+        page = kids.get(options.getPage()-1);
+      
+
+      // AcroForm aus dem Root dict besorgen und Annotation einfügen
+      PDAcroForm acroForm = root.getAcroForm();
+      root.getCOSObject().setNeedToBeUpdate(true); 
+
+      if (acroForm==null) 
+      {
+        acroForm = new PDAcroForm(this);
+        root.setAcroForm(acroForm);
+      } else 
+        acroForm.getCOSObject().setNeedToBeUpdate(true);
+      
+      /*
+       *  For invisible signatures, the annotation has a rectangle array with values [ 0 0 0 0 ]. 
+       *  This annotation is usually attached to the viewed page when the signature is created. 
+       *  Despite not having an appearance, the annotation AP and N dictionaries may be present 
+       *  in some versions of Acrobat. If present, N references the DSBlankXObj (blank) XObject.
+       */
+
+      // Annotation / Field für die Signatur erzeugen
+      PDSignatureField signatureField = new PDSignatureField(acroForm);
+      signatureField.setSignature(sigObject);              // Signaturobjekt vermerken
+      signatureField.getWidget().setPage(page);            // Rückverkettung 
+      
+      // AcroForm Fields setzen
+      List acroFormFields = acroForm.getFields();
+      COSDictionary acroFormDict = acroForm.getDictionary();
+      acroFormDict.setDirect(true);
+      acroFormDict.setInt("SigFlags", 3);
+      acroFormFields.add(signatureField);
+
+      // Objekte aus der visuellen Signatur besorgen
+      COSDocument visualSignature = options.getVisualSignature();
+
+      // Fallunterscheidung zwischen sichtbarer und unsichtbarer Signatur vorbereiten
+      if (visualSignature == null) // unsichtbare Signatur
+      {
+        // Rectangle fuer unsichtbare Signatur auf 0 0 0 0 setzen
+        signatureField.getWidget().setRectangle(new PDRectangle());  // rectangle array [ 0 0 0 0 ]
+        // AcroForm leere DefaultRessource setzen
+        acroFormDict.setItem("DR", null);
+        // Leeres Appearance-Dictionary setzten
+        PDAppearanceDictionary ap = new PDAppearanceDictionary();
+        COSStream apsStream = new COSStream(getDocument().getScratchFile());
+        apsStream.createUnfilteredStream();
+        PDAppearanceStream aps = new PDAppearanceStream(apsStream);
+        COSDictionary cosObject = (COSDictionary)aps.getCOSObject();
+        cosObject.setItem(COSName.SUBTYPE, COSName.getPDFName("Form"));
+        cosObject.setItem(COSName.BBOX, new PDRectangle());
+        
+        ap.setNormalAppearance(aps);
+        ap.getDictionary().setDirect(true);
+        signatureField.getWidget().setAppearance(ap);
+      }
+      else // sichtbare Signatur
+      {
+        // Visuelle Objekte besorgen
+        List<COSObject> cosObjects = visualSignature.getObjects();
+
+        boolean annotNotFound = true;
+        boolean sigFieldNotFound = true;
+
+        for ( COSObject cosObject : cosObjects )
+        {
+          COSBase base = cosObject.getObject();
+          if (base != null && base instanceof COSDictionary)
+          {
+            COSBase ft = ((COSDictionary)base).getItem(COSName.getPDFName("FT"));
+            COSBase type = ((COSDictionary)base).getItem(COSName.TYPE);
+            COSBase apDict = ((COSDictionary)base).getItem(COSName.AP);
+            
+            // Nach Signatur-Annotation suchen
+            if (annotNotFound && COSName.getPDFName("Annot").equals(type))
+            {
+              COSDictionary cosBaseDict = (COSDictionary)base;
+              
+              // Rectangle fuer visuelle Signatur auslesen und setzen
+              COSArray rectAry = (COSArray)cosBaseDict.getItem(COSName.getPDFName("Rect"));
+              PDRectangle rect = new PDRectangle(rectAry);
+              signatureField.getWidget().setRectangle(rect);
+              annotNotFound = false;
+            }
+            
+            // Nach Signatur-Field suchen
+            if (sigFieldNotFound && COSName.getPDFName("Sig").equals(ft) && apDict != null)
+            {
+              COSDictionary cosBaseDict = (COSDictionary)base;
+              
+              // Appearance Dictionary auslesen und setzen
+              PDAppearanceDictionary ap = new PDAppearanceDictionary((COSDictionary)cosBaseDict.getItem(COSName.AP));
+              ap.getDictionary().setDirect(true);
+              signatureField.getWidget().setAppearance(ap);
+              
+              // AcroForm DefaultRessource auslesen und setzen
+              COSBase dr = cosBaseDict.getItem(COSName.getPDFName("DR"));
+              dr.setDirect(true);
+              dr.setNeedToBeUpdate(true);
+              acroFormDict.setItem("DR", dr);
+              sigFieldNotFound=false;
+            }
+          }
+        }
+        
+        if (annotNotFound || sigFieldNotFound )
+          throw new SignatureException(SignatureException.VISUAL_SIGNATURE_INVALID, "Could not read all needed objects from template");
+      }
+      
+      // Seite besorgen und Signatur-Annotation anbringen
+      List annotations = page.getAnnotations();
+      if (annotations== null) 
+      {
+        annotations = new COSArrayList();
+      }
+      annotations.add(signatureField.getWidget());
+      page.setAnnotations(annotations);
+      page.getCOSObject().setNeedToBeUpdate(true);
+      
+    }
+
     /**
      * Remove the page from the document.
      *
@@ -473,6 +655,17 @@ public class PDDocument implements Pagea
         encParameters = encDictionary;
     }
 
+    public PDSignature getSignatureDictionary() throws IOException 
+    {
+      COSDictionary signatureDictionary = document.getLastSignatureDictionary();
+
+      if (signatureDictionary!= null)
+      {
+        return new PDSignature(signatureDictionary);
+      }
+      return null;
+    }
+    
     /**
      * This will determine if this is the user password.  This only applies when
      * the document is encrypted and uses standard encryption.
@@ -486,6 +679,7 @@ public class PDDocument implements Pagea
      *
      * @deprecated
      */
+    @Deprecated
     public boolean isUserPassword( String password ) throws IOException, CryptographyException
     {
             return false;
@@ -537,6 +731,7 @@ public class PDDocument implements Pagea
      *
      * @deprecated
      */
+    @Deprecated
     public boolean isOwnerPassword( String password ) throws IOException, CryptographyException
     {
             return false;
@@ -608,6 +803,7 @@ public class PDDocument implements Pagea
      *
      * @deprecated use <code>getCurrentAccessPermission</code> instead
      */
+    @Deprecated
     public boolean wasDecryptedWithOwnerPassword()
     {
         return false;
@@ -651,6 +847,7 @@ public class PDDocument implements Pagea
      *
      * @deprecated Do not rely on this method anymore.
      */
+    @Deprecated
     public String getOwnerPasswordForEncryption()
     {
         return null;
@@ -665,6 +862,7 @@ public class PDDocument implements Pagea
      *
      * @deprecated Do not rely on this method anymore.
      */
+    @Deprecated
     public String getUserPasswordForEncryption()
     {
         return null;
@@ -679,6 +877,7 @@ public class PDDocument implements Pagea
      * @deprecated Do not rely on this method anymore. It is the responsibility of
      * COSWriter to hold this state
      */
+    @Deprecated
     public boolean willEncryptWhenSaving()
     {
         return false;
@@ -690,6 +889,7 @@ public class PDDocument implements Pagea
      * @deprecated Do not rely on this method anymore. It is the responsability of
      * COSWriter to hold this state.
      */
+    @Deprecated
     public void clearWillEncryptWhenSaving()
     {
         //method is deprecated.
@@ -858,7 +1058,7 @@ public class PDDocument implements Pagea
      */
     public static PDDocument load( InputStream input, RandomAccess scratchFile ) throws IOException
     {
-        PDFParser parser = new PDFParser( new BufferedInputStream( input ), scratchFile );
+        PDFParser parser = new PDFParser( new BufferedInputStream( input ) , scratchFile );
         parser.parse();
         return parser.getPDDocument();
     }
@@ -923,6 +1123,31 @@ public class PDDocument implements Pagea
         }
     }
 
+    public void saveIncremental( String fileName ) throws IOException, COSVisitorException
+    {
+        saveIncremental( new FileInputStream( fileName ) , new FileOutputStream( fileName , true) );
+    }
+    
+    public void saveIncremental( FileInputStream input, OutputStream output ) throws IOException, COSVisitorException
+    {
+        //update the count in case any pages have been added behind the scenes.
+        getDocumentCatalog().getPages().updateCount();
+        COSWriter writer = null;
+        try
+        {
+            writer = new COSWriter( output, input );
+            writer.write( this );
+            writer.close();
+        }
+        finally
+        {
+            if( writer != null )
+            {
+                writer.close();
+            }
+        }
+    }
+
     /**
      * This will return the total page count of the PDF document.  Note: This method
      * is deprecated in favor of the getNumberOfPages method.  The getNumberOfPages is
@@ -932,6 +1157,7 @@ public class PDDocument implements Pagea
      * @return The total number of pages in the PDF document.
      * @deprecated Use the getNumberOfPages method instead!
      */
+    @Deprecated
     public int getPageCount()
     {
         return getNumberOfPages();
@@ -955,6 +1181,7 @@ public class PDDocument implements Pagea
      * @return page format
      * @throws IndexOutOfBoundsException if the page index is invalid
      */
+    @Deprecated
     public PageFormat getPageFormat(int pageIndex)
     {
         try {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java Sat Apr 16 02:38:31 2011
@@ -617,6 +617,16 @@ public abstract class PDAnnotation imple
     }
 
     /**
+     * This will set the corresponding page for this annotation.
+     * 
+     * @param page is the corresponding page
+     */
+    public void setPage(PDPage page)
+    {
+        this.getDictionary().setItem(COSName.P, page);
+    }
+    
+    /**
      * This will retrieve the corresponding page of this annotation.
      * 
      * @return the corresponding page

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java Sat Apr 16 02:38:31 2011
@@ -16,56 +16,315 @@
  */
 package org.apache.pdfbox.pdmodel.interactive.digitalsignature;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+
+import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
-
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSString;
+import org.apache.pdfbox.pdfwriter.COSFilterInputStream;
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
 
 /**
  * This represents a digital signature that can be attached to a document.
- *
+ * 
  * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @author Thomas Chojecki
  * @version $Revision: 1.2 $
  */
 public class PDSignature implements COSObjectable
 {
-    private COSDictionary sig;
 
-    /**
-     * Default constructor.
-     */
-    public PDSignature()
+  private COSDictionary dictionary;
+
+  /**
+   * A signature filter value.
+   */
+  public static final COSName FILTER_ADOBE_PPKLITE = COSName.ADOBE_PPKLITE;
+
+  /**
+   * A signature filter value.
+   */
+  public static final COSName FILTER_ENTRUST_PPKEF = COSName.ENTRUST_PPKEF;
+
+  /**
+   * A signature filter value.
+   */
+  public static final COSName FILTER_CICI_SIGNIT = COSName.CICI_SIGNIT;
+
+  /**
+   * A signature filter value.
+   */
+  public static final COSName FILTER_VERISIGN_PPKVS = COSName.VERISIGN_PPKVS;
+
+  /**
+   * A signature subfilter value.
+   */
+  public static final COSName SUBFILTER_ADBE_X509_RSA_SHA1 = COSName.ADBE_X509_RSA_SHA1;
+
+  /**
+   * A signature subfilter value.
+   */
+  public static final COSName SUBFILTER_ADBE_PKCS7_DETACHED = COSName.ADBE_PKCS7_DETACHED;
+
+  /**
+   * A signature subfilter value.
+   */
+  public static final COSName SUBFILTER_ETSI_CADES_DETACHED = COSName.getPDFName("ETSI.CAdES.detached");
+
+  /**
+   * A signature subfilter value.
+   */
+  public static final COSName SUBFILTER_ADBE_PKCS7_SHA1 = COSName.ADBE_PKCS7_SHA1;
+
+  /**
+   * Default constructor.
+   */
+  public PDSignature()
+  {
+    dictionary = new COSDictionary();
+    dictionary.setItem(COSName.TYPE, COSName.SIG);
+  }
+
+  /**
+   * Constructor.
+   * 
+   * @param dict The signature dictionary.
+   */
+  public PDSignature(COSDictionary dict)
+  {
+    dictionary = dict;
+  }
+
+  /**
+   * Convert this standard java object to a COS object.
+   * 
+   * @return The cos object that matches this Java object.
+   */
+  public COSBase getCOSObject()
+  {
+    return getDictionary();
+  }
+
+  /**
+   * Convert this standard java object to a COS dictionary.
+   * 
+   * @return The COS dictionary that matches this Java object.
+   */
+  public COSDictionary getDictionary()
+  {
+    return dictionary;
+  }
+
+  public void setFilter(COSName filter)
+  {
+    dictionary.setItem(COSName.FILTER, filter);
+  }
+
+  /**
+   * Set a subfilter that specify the signature that should be used. 
+   * 
+   * @param subfilter the subfilter that shall be used.
+   */
+  public void setSubFilter(COSName subfilter)
+  {
+    dictionary.setItem(COSName.SUBFILTER, subfilter);
+  }
+
+  public void setName(String name)
+  {
+    dictionary.setString(COSName.NAME, name);
+  }
+
+  public void setLocation(String location)
+  {
+    dictionary.setString(COSName.LOCATION, location);
+  }
+
+  public void setReason(String reason)
+  {
+    dictionary.setString(COSName.REASON, reason);
+  }
+
+  public void setSignDate(Calendar cal)
+  {
+    dictionary.setDate("M", cal);
+  }
+
+  public String getFilter()
+  {
+    return ((COSName)dictionary.getItem(COSName.FILTER)).getName();
+  }
+
+  public String getSubFilter()
+  {
+    return ((COSName)dictionary.getItem(COSName.SUBFILTER)).getName();
+  }
+
+  public String getName()
+  {
+    return dictionary.getString(COSName.NAME);
+  }
+
+  public String getLocation()
+  {
+    return dictionary.getString(COSName.LOCATION);
+  }
+
+  public String getReason()
+  {
+    return dictionary.getString(COSName.REASON);
+  }
+
+  public Calendar getSignDate()
+  {
+    try
     {
-        sig = new COSDictionary();
+      return dictionary.getDate("M");
     }
-
-    /**
-     * Constructor.
-     *
-     * @param s The signature dictionary.
-     */
-    public PDSignature( COSDictionary s )
+    catch (IOException e)
     {
-        sig = s;
+      return null;
     }
+  }
 
-    /**
-     * Convert this standard java object to a COS object.
-     *
-     * @return The cos object that matches this Java object.
-     */
-    public COSBase getCOSObject()
+  public void setByteRange(int[] range) 
+  {
+    if (range.length!=4)
+      return;
+
+    COSArray ary = new COSArray();
+    for ( int i : range )
     {
-        return sig;
+      ary.add(COSInteger.get(i));
     }
+    
+    dictionary.setItem("ByteRange", ary);
+  }
+
+  /**
+   * Read out the byterange from the file
+   * 
+   * @return a integer array with the byterange
+   */
+  public int[] getByteRange()
+  {
+    COSArray byteRange = (COSArray)dictionary.getDictionaryObject("ByteRange");
+    int[] ary = new int[byteRange.size()];
+    for (int i = 0; i<ary.length;++i)
+      ary[i] = byteRange.getInt(i);
+    
+    return ary;
+  }
+  
+  /**
+   * Will return the embedded signature between the byterange gap.
+   * 
+   * @param pdfFile The signed pdf file as InputStream
+   * @return a byte array containing the signature
+   * @throws IOException if the pdfFile can't be read
+   */
+  public byte[] getContents(InputStream pdfFile) throws IOException
+  {
+    int[] byteRange = getByteRange();
+    int begin = byteRange[0]+byteRange[1]+1;
+    int end = byteRange[2]-begin;
+    
+    return getContents(new COSFilterInputStream(pdfFile,new int[] {begin,end}));
+  }
+  
+  /**
+   * Will return the embedded signature between the byterange gap.
+   * 
+   * @param pdfFile The signed pdf file as byte array
+   * @return a byte array containing the signature
+   * @throws IOException if the pdfFile can't be read
+   */
+  public byte[] getContents(byte[] pdfFile) throws IOException
+  {
+    int[] byteRange = getByteRange();
+    int begin = byteRange[0]+byteRange[1]+1;
+    int end = byteRange[2]-begin;
+    
+    return getContents(new COSFilterInputStream(pdfFile,new int[] {begin,end}));
+  }
 
-    /**
-     * Convert this standard java object to a COS object.
-     *
-     * @return The cos object that matches this Java object.
-     */
-    public COSDictionary getCOSDictionary()
+  private byte[] getContents(COSFilterInputStream fis) throws IOException 
+  {
+    ByteArrayOutputStream byteOS = new ByteArrayOutputStream(1024);
+    byte[] buffer = new byte[1024];
+    int c;
+    while ((c = fis.read(buffer)) != -1)
+    {
+      // Filter < and (
+      if(buffer[0]==0x3C || buffer[0]==0x28)
+        byteOS.write(buffer, 1, c);
+      // Filter > and )
+      else if(buffer[c-1]==0x3E || buffer[c-1]==0x29)
+        byteOS.write(buffer, 0, c-1);
+      else 
+        byteOS.write(buffer, 0, c);
+    }
+    fis.close();
+    
+    return COSString.createFromHexString(byteOS.toString()).getBytes();
+  }
+  
+  public void setContents(byte[] bytes)
+  {
+    COSString string = new COSString(bytes);
+    string.setForceHexForm(true);
+    dictionary.setItem("Contents", string);
+  }
+  
+  /**
+   * Will return the signed content of the document.
+   * 
+   * @param pdfFile The signed pdf file as InputStream
+   * @return a byte array containing only the signed part of the content
+   * @throws IOException if the pdfFile can't be read
+   */
+  public byte[] getSignedContent(InputStream pdfFile) throws IOException
+  {
+    COSFilterInputStream fis=null;
+    
+    try 
+    {
+    fis = new COSFilterInputStream(pdfFile,getByteRange());
+    return fis.toByteArray();
+    } 
+    finally 
+    {
+      if (fis != null)
+        fis.close();
+    }
+  }
+  
+  /**
+   * Will return the signed content of the document.
+   * 
+   * @param pdfFile The signed pdf file as byte array
+   * @return a byte array containing only the signed part of the content
+   * @throws IOException if the pdfFile can't be read
+   */
+  public byte[] getSignedContent(byte[] pdfFile) throws IOException
+  {
+    COSFilterInputStream fis=null;
+    
+    try 
+    {
+    fis = new COSFilterInputStream(pdfFile,getByteRange());
+    return fis.toByteArray();
+    } 
+    finally 
     {
-        return sig;
+      if (fis != null)
+        fis.close();
     }
+  }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java Sat Apr 16 02:38:31 2011
@@ -574,6 +574,7 @@ public abstract class PDField implements
      *
      * @return A string representation of this field.
      */
+    @Override
     public String toString()
     {
         return "" + getDictionary().getDictionaryObject( COSName.V );

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java?rev=1092855&r1=1092854&r2=1092855&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java Sat Apr 16 02:38:31 2011
@@ -97,7 +97,7 @@ public class PDFieldFactory
         }
         else if( isSignature( pdField ) )
         {
-            pdField = new PDSignature( acroForm, field );
+            pdField = new PDSignatureField( acroForm, field );
         }
         else
         {