From 13d6dc3a6a5e8bd3c17997351a0e6f087eb301a2 Mon Sep 17 00:00:00 2001 From: tknall Date: Tue, 25 Nov 2008 12:04:30 +0000 Subject: Removing itext from source. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@302 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../lowagie/text/pdf/PdfSignatureAppearance.java | 1349 -------------------- 1 file changed, 1349 deletions(-) delete mode 100644 src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java (limited to 'src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java') diff --git a/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java b/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java deleted file mode 100644 index 52b186c..0000000 --- a/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * Copyright 2004 by Paulo Soares. - * - * The contents of this file are subject to the Mozilla Public License Version 1.1 - * (the "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the License. - * - * The Original Code is 'iText, a free JAVA-PDF library'. - * - * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by - * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. - * All Rights Reserved. - * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer - * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. - * - * Contributor(s): all the names of the contributors are added in the source code - * where applicable. - * - * Alternatively, the contents of this file may be used under the terms of the - * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the - * provisions of LGPL are applicable instead of those above. If you wish to - * allow use of your version of this file only under the terms of the LGPL - * License and not to allow others to use your version of this file under - * the MPL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the LGPL. - * If you do not delete the provisions above, a recipient may use your version - * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the MPL as stated above or under the terms of the GNU - * Library General Public License as published by the Free Software Foundation; - * either version 2 of the License, or any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more - * details. - * - * If you didn't download this code from the following link, you should check if - * you aren't using an obsolete version: - * http://www.lowagie.com/iText/ - */ -package com.lowagie.text.pdf; - -import com.lowagie.text.Rectangle; -import com.lowagie.text.ExceptionConverter; -import com.lowagie.text.Phrase; -import com.lowagie.text.Font; -import com.lowagie.text.Element; -import com.lowagie.text.Image; -import com.lowagie.text.DocumentException; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Iterator; -import java.text.SimpleDateFormat; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.security.cert.CRL; -import java.security.PrivateKey; -import java.io.OutputStream; -import java.io.IOException; -import java.io.EOFException; -import java.io.RandomAccessFile; -import java.io.File; -import java.io.InputStream; - -/** - * This class takes care of the cryptographic options and appearances that form a signature. - */ -public class PdfSignatureAppearance { - - /** - * The self signed filter. - */ - public static final PdfName SELF_SIGNED = PdfName.ADOBE_PPKLITE; - /** - * The VeriSign filter. - */ - public static final PdfName VERISIGN_SIGNED = PdfName.VERISIGN_PPKVS; - /** - * The Windows Certificate Security. - */ - public static final PdfName WINCER_SIGNED = PdfName.ADOBE_PPKMS; - - private static final float topSection = 0.3f; - private static final float margin = 2; - private Rectangle rect; - private Rectangle pageRect; - private PdfTemplate app[] = new PdfTemplate[5]; - private PdfTemplate frm; - private PdfStamperImp writer; - private String layer2Text; - private String reason; - private String location; - private Calendar signDate; - private String provider; - private int page = 1; - private String fieldName; - private PrivateKey privKey; - private Certificate[] certChain; - private CRL[] crlList; - private PdfName filter; - private boolean newField; - private ByteBuffer sigout; - private OutputStream originalout; - private File tempFile; - private PdfDictionary cryptoDictionary; - private PdfStamper stamper; - private boolean preClosed = false; - private PdfSigGenericPKCS sigStandard; - private int range[]; - private RandomAccessFile raf; - private int rangePosition = 0; - private byte bout[]; - private int boutLen; - private byte externalDigest[]; - private byte externalRSAdata[]; - private String digestEncryptionAlgorithm; - private HashMap exclusionLocations; - - PdfSignatureAppearance(PdfStamperImp writer) { - this.writer = writer; - signDate = new GregorianCalendar(); - fieldName = getNewSigName(); - } - - /** - * Sets the signature text identifying the signer. - * @param text the signature text identifying the signer. If null or not set - * a standard description will be used - */ - public void setLayer2Text(String text) { - layer2Text = text; - } - - /** - * Gets the signature text identifying the signer if set by setLayer2Text(). - * @return the signature text identifying the signer - */ - public String getLayer2Text() { - return layer2Text; - } - - /** - * Sets the text identifying the signature status. - * @param text the text identifying the signature status. If null or not set - * the description "Signature Not Verified" will be used - */ - public void setLayer4Text(String text) { - layer4Text = text; - } - - /** - * Gets the text identifying the signature status if set by setLayer4Text(). - * @return the text identifying the signature status - */ - public String getLayer4Text() { - return layer4Text; - } - - /** - * Gets the rectangle representing the signature dimensions. - * @return the rectangle representing the signature dimensions. It may be null - * or have zero width or height for invisible signatures - */ - public Rectangle getRect() { - return rect; - } - - /** - * Gets the visibility status of the signature. - * @return the visibility status of the signature - */ - public boolean isInvisible() { - return (rect == null || rect.width() == 0 || rect.height() == 0); - } - - /** - * Sets the cryptographic parameters. - * @param privKey the private key - * @param certChain the certificate chain - * @param crlList the certificate revocation list. It may be null - * @param filter the crytographic filter type. It can be SELF_SIGNED, VERISIGN_SIGNED or WINCER_SIGNED - */ - public void setCrypto(PrivateKey privKey, Certificate[] certChain, CRL[] crlList, PdfName filter) { - this.privKey = privKey; - this.certChain = certChain; - this.crlList = crlList; - this.filter = filter; - } - - /** - * Sets the signature to be visible. It creates a new visible signature field. - * @param pageRect the position and dimension of the field in the page - * @param page the page to place the field. The fist page is 1 - * @param fieldName the field name or null to generate automatically a new field name - */ - public void setVisibleSignature(Rectangle pageRect, int page, String fieldName) { - if (fieldName != null) { - if (fieldName.indexOf('.') >= 0) - throw new IllegalArgumentException("Field names cannot contain a dot."); - AcroFields af = writer.getAcroFields(); - AcroFields.Item item = af.getFieldItem(fieldName); - if (item != null) - throw new IllegalArgumentException("The field " + fieldName + " already exists."); - this.fieldName = fieldName; - } - if (page < 1 || page > writer.reader.getNumberOfPages()) - throw new IllegalArgumentException("Invalid page number: " + page); - this.pageRect = new Rectangle(pageRect); - this.pageRect.normalize(); - rect = new Rectangle(this.pageRect.width(), this.pageRect.height()); - this.page = page; - newField = true; - } - - /** - * Sets the signature to be visible. An empty signature field with the same name must already exist. - * @param fieldName the existing empty signature field name - */ - public void setVisibleSignature(String fieldName) { - AcroFields af = writer.getAcroFields(); - AcroFields.Item item = af.getFieldItem(fieldName); - if (item == null) - throw new IllegalArgumentException("The field " + fieldName + " does not exist."); - PdfDictionary merged = (PdfDictionary)item.merged.get(0); - if (!PdfName.SIG.equals(PdfReader.getPdfObject(merged.get(PdfName.FT)))) - throw new IllegalArgumentException("The field " + fieldName + " is not a signature field."); - this.fieldName = fieldName; - PdfArray r = (PdfArray)PdfReader.getPdfObject(merged.get(PdfName.RECT)); - ArrayList ar = r.getArrayList(); - float llx = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(0))).floatValue(); - float lly = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(1))).floatValue(); - float urx = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(2))).floatValue(); - float ury = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(3))).floatValue(); - pageRect = new Rectangle(llx, lly, urx, ury); - pageRect.normalize(); - page = ((Integer)item.page.get(0)).intValue(); - int rotation = writer.reader.getPageRotation(page); - Rectangle pageSize = writer.reader.getPageSizeWithRotation(page); - switch (rotation) { - case 90: - pageRect = new Rectangle( - pageRect.bottom(), - pageSize.top() - pageRect.left(), - pageRect.top(), - pageSize.top() - pageRect.right()); - break; - case 180: - pageRect = new Rectangle( - pageSize.right() - pageRect.left(), - pageSize.top() - pageRect.bottom(), - pageSize.right() - pageRect.right(), - pageSize.top() - pageRect.top()); - break; - case 270: - pageRect = new Rectangle( - pageSize.right() - pageRect.bottom(), - pageRect.left(), - pageSize.right() - pageRect.top(), - pageRect.right()); - break; - } - if (rotation != 0) - pageRect.normalize(); - rect = new Rectangle(this.pageRect.width(), this.pageRect.height()); - } - - /** - * Gets a template layer to create a signature appearance. The layers can go from 0 to 4. - *

- * Consult PPKAppearances.pdf - * for further details. - * @param layer the layer - * @return a template - */ - public PdfTemplate getLayer(int layer) { - if (layer < 0 || layer >= app.length) - return null; - PdfTemplate t = app[layer]; - if (t == null) { - t = app[layer] = new PdfTemplate(writer); - t.setBoundingBox(rect); - writer.addDirectTemplateSimple(t, new PdfName("n" + layer)); - } - return t; - } - - /** - * Gets the template that aggregates all appearance layers. This corresponds to the /FRM resource. - *

- * Consult PPKAppearances.pdf - * for further details. - * @return the template that aggregates all appearance layers - */ - public PdfTemplate getTopLayer() { - if (frm == null) { - frm = new PdfTemplate(writer); - frm.setBoundingBox(rect); - writer.addDirectTemplateSimple(frm, new PdfName("FRM")); - } - return frm; - } - - /** - * Gets the main appearance layer. - *

- * Consult PPKAppearances.pdf - * for further details. - * @return the main appearance layer - * @throws DocumentException on error - * @throws IOException on error - */ - public PdfTemplate getAppearance() throws DocumentException, IOException { - if (app[0] == null) { - PdfTemplate t = app[0] = new PdfTemplate(writer); - t.setBoundingBox(new Rectangle(100, 100)); - writer.addDirectTemplateSimple(t, new PdfName("n0")); - t.setLiteral("% DSBlank\n"); - } - if (app[1] == null && !acro6Layers) { - PdfTemplate t = app[1] = new PdfTemplate(writer); - t.setBoundingBox(new Rectangle(100, 100)); - writer.addDirectTemplateSimple(t, new PdfName("n1")); - t.setLiteral(questionMark); - } - if (app[2] == null) { - String text; - if (layer2Text == null) { - StringBuffer buf = new StringBuffer(); - buf.append("Digitally signed by ").append(PdfPKCS7.getSubjectFields((X509Certificate)certChain[0]).getField("CN")).append("\n"); - SimpleDateFormat sd = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z"); - buf.append("Date: ").append(sd.format(signDate.getTime())); - if (reason != null) - buf.append("\n").append("Reason: ").append(reason); - if (location != null) - buf.append("\n").append("Location: ").append(location); - text = buf.toString(); - } - else - text = layer2Text; - PdfTemplate t = app[2] = new PdfTemplate(writer); - t.setBoundingBox(rect); - writer.addDirectTemplateSimple(t, new PdfName("n2")); - if (image != null) { - if (imageScale == 0) { - t.addImage(image, rect.width(), 0, 0, rect.height(), 0, 0); - } - else { - float usableScale = imageScale; - if (imageScale < 0) - usableScale = Math.min(rect.width() / image.width(), rect.height() / image.height()); - float w = image.width() * usableScale; - float h = image.height() * usableScale; - float x = (rect.width() - w) / 2; - float y = (rect.height() - h) / 2; - t.addImage(image, w, 0, 0, h, x, y); - } - } - Font font; - if (layer2Font == null) - font = new Font(); - else - font = new Font(layer2Font); - float size = font.size(); - if (size <= 0) { - Rectangle sr = new Rectangle(rect.width() - 2 * margin, rect.height() * (1 - topSection) - 2 * margin); - size = fitText(font, text, sr, 12, runDirection); - } - ColumnText ct = new ColumnText(t); - ct.setRunDirection(runDirection); - ct.setSimpleColumn(new Phrase(text, font), margin, 0, rect.width() - margin, rect.height() * (1 - topSection) - margin, size, Element.ALIGN_LEFT); - ct.go(); - } - if (app[3] == null && !acro6Layers) { - PdfTemplate t = app[3] = new PdfTemplate(writer); - t.setBoundingBox(new Rectangle(100, 100)); - writer.addDirectTemplateSimple(t, new PdfName("n3")); - t.setLiteral("% DSBlank\n"); - } - if (app[4] == null && !acro6Layers) { - PdfTemplate t = app[4] = new PdfTemplate(writer); - t.setBoundingBox(new Rectangle(0, rect.height() * (1 - topSection), rect.right(), rect.top())); - writer.addDirectTemplateSimple(t, new PdfName("n4")); - Font font; - if (layer2Font == null) - font = new Font(); - else - font = new Font(layer2Font); - float size = font.size(); - String text = "Signature Not Verified"; - if (layer4Text != null) - text = layer4Text; - Rectangle sr = new Rectangle(rect.width() - 2 * margin, rect.height() * topSection - 2 * margin); - size = fitText(font, text, sr, 15, runDirection); - ColumnText ct = new ColumnText(t); - ct.setRunDirection(runDirection); - ct.setSimpleColumn(new Phrase(text, font), margin, 0, rect.width() - margin, rect.height() - margin, size, Element.ALIGN_LEFT); - ct.go(); - } - int rotation = writer.reader.getPageRotation(page); - Rectangle rotated = new Rectangle(rect); - int n = rotation; - while (n > 0) { - rotated = rotated.rotate(); - n -= 90; - } - if (frm == null) { - frm = new PdfTemplate(writer); - frm.setBoundingBox(rotated); - writer.addDirectTemplateSimple(frm, new PdfName("FRM")); - float scale = Math.min(rect.width(), rect.height()) * 0.9f; - float x = (rect.width() - scale) / 2; - float y = (rect.height() - scale) / 2; - scale /= 100; - if (rotation == 90) - frm.concatCTM(0, 1, -1, 0, rect.height(), 0); - else if (rotation == 180) - frm.concatCTM(-1, 0, 0, -1, rect.width(), rect.height()); - else if (rotation == 270) - frm.concatCTM(0, -1, 1, 0, 0, rect.width()); - frm.addTemplate(app[0], 0, 0); - if (!acro6Layers) - frm.addTemplate(app[1], scale, 0, 0, scale, x, y); - frm.addTemplate(app[2], 0, 0); - if (!acro6Layers) { - frm.addTemplate(app[3], scale, 0, 0, scale, x, y); - frm.addTemplate(app[4], 0, 0); - } - } - PdfTemplate napp = new PdfTemplate(writer); - napp.setBoundingBox(rotated); - writer.addDirectTemplateSimple(napp, null); - napp.addTemplate(frm, 0, 0); - return napp; - } - - /** - * Fits the text to some rectangle adjusting the font size as needed. - * @param font the font to use - * @param text the text - * @param rect the rectangle where the text must fit - * @param maxFontSize the maximum font size - * @param runDirection the run direction - * @return the calculated font size that makes the text fit - */ - public static float fitText(Font font, String text, Rectangle rect, float maxFontSize, int runDirection) { - try { - ColumnText ct = null; - int status = 0; - if (maxFontSize <= 0) { - int cr = 0; - int lf = 0; - char t[] = text.toCharArray(); - for (int k = 0; k < t.length; ++k) { - if (t[k] == '\n') - ++lf; - else if (t[k] == '\r') - ++cr; - } - int minLines = Math.max(cr, lf) + 1; - maxFontSize = Math.abs(rect.height()) / minLines - 0.001f; - } - font.setSize(maxFontSize); - Phrase ph = new Phrase(text, font); - ct = new ColumnText(null); - ct.setSimpleColumn(ph, rect.left(), rect.bottom(), rect.right(), rect.top(), maxFontSize, Element.ALIGN_LEFT); - ct.setRunDirection(runDirection); - status = ct.go(true); - if ((status & ColumnText.NO_MORE_TEXT) != 0) - return maxFontSize; - float precision = 0.1f; - float min = 0; - float max = maxFontSize; - float size = maxFontSize; - for (int k = 0; k < 50; ++k) { //just in case it doesn't converge - size = (min + max) / 2; - ct = new ColumnText(null); - font.setSize(size); - ct.setSimpleColumn(new Phrase(text, font), rect.left(), rect.bottom(), rect.right(), rect.top(), size, Element.ALIGN_LEFT); - ct.setRunDirection(runDirection); - status = ct.go(true); - if ((status & ColumnText.NO_MORE_TEXT) != 0) { - if (max - min < size * precision) - return size; - min = size; - } - else - max = size; - } - return size; - } - catch (Exception e) { - throw new ExceptionConverter(e); - } - } - - /** - * Sets the digest/signature to an external calculated value. - * @param digest the digest. This is the actual signature - * @param RSAdata the extra data that goes into the data tag in PKCS#7 - * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest - * is also null. If the digest is not null - * then it may be "RSA" or "DSA" - */ - public void setExternalDigest(byte digest[], byte RSAdata[], String digestEncryptionAlgorithm) { - externalDigest = digest; - externalRSAdata = RSAdata; - this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; - } - - /** - * Gets the signing reason. - * @return the signing reason - */ - public String getReason() { - return this.reason; - } - - /** - * Sets the signing reason. - * @param reason the signing reason - */ - public void setReason(String reason) { - this.reason = reason; - } - - /** - * Gets the signing location. - * @return the signing location - */ - public String getLocation() { - return this.location; - } - - /** - * Sets the signing location. - * @param location the signing location - */ - public void setLocation(String location) { - this.location = location; - } - - /** - * Returns the Cryptographic Service Provider that will sign the document. - * @return provider the name of the provider, for example "SUN", - * or null to use the default provider. - */ - public String getProvider() { - return this.provider; - } - - /** - * Sets the Cryptographic Service Provider that will sign the document. - * - * @param provider the name of the provider, for example "SUN", or - * null to use the default provider. - */ - public void setProvider(String provider) { - this.provider = provider; - } - - /** - * Gets the private key. - * @return the private key - */ - public java.security.PrivateKey getPrivKey() { - return privKey; - } - - /** - * Gets the certificate chain. - * @return the certificate chain - */ - public java.security.cert.Certificate[] getCertChain() { - return this.certChain; - } - - /** - * Gets the certificate revocation list. - * @return the certificate revocation list - */ - public java.security.cert.CRL[] getCrlList() { - return this.crlList; - } - - /** - * Gets the filter used to sign the document. - * @return the filter used to sign the document - */ - public com.lowagie.text.pdf.PdfName getFilter() { - return filter; - } - - /** - * Checks if a new field was created. - * @return true if a new field was created, false if signing - * an existing field or if the signature is invisible - */ - public boolean isNewField() { - return this.newField; - } - - /** - * Gets the page number of the field. - * @return the page number of the field - */ - public int getPage() { - return page; - } - - /** - * Gets the field name. - * @return the field name - */ - public java.lang.String getFieldName() { - return fieldName; - } - - /** - * Gets the rectangle that represent the position and dimension of the signature in the page. - * @return the rectangle that represent the position and dimension of the signature in the page - */ - public com.lowagie.text.Rectangle getPageRect() { - return pageRect; - } - - /** - * Gets the signature date. - * @return the signature date - */ - public java.util.Calendar getSignDate() { - return signDate; - } - - /** - * Sets the signature date. - * @param signDate the signature date - */ - public void setSignDate(java.util.Calendar signDate) { - this.signDate = signDate; - } - - com.lowagie.text.pdf.ByteBuffer getSigout() { - return sigout; - } - - void setSigout(com.lowagie.text.pdf.ByteBuffer sigout) { - this.sigout = sigout; - } - - java.io.OutputStream getOriginalout() { - return originalout; - } - - void setOriginalout(java.io.OutputStream originalout) { - this.originalout = originalout; - } - - /** - * Gets the temporary file. - * @return the temporary file or null is the document is created in memory - */ - public java.io.File getTempFile() { - return tempFile; - } - - void setTempFile(java.io.File tempFile) { - this.tempFile = tempFile; - } - - /** - * Gets a new signature fied name that doesn't clash with any existing name. - * @return a new signature fied name - */ - public String getNewSigName() { - AcroFields af = writer.getAcroFields(); - String name = "Signature"; - int step = 0; - boolean found = false; - while (!found) { - ++step; - String n1 = name + step; - if (af.getFieldItem(n1) != null) - continue; - n1 += "."; - found = true; - for (Iterator it = af.getFields().keySet().iterator(); it.hasNext();) { - String fn = (String)it.next(); - if (fn.startsWith(n1)) { - found = false; - break; - } - } - } - name += step; - return name; - } - - /** - * This is the first method to be called when using external signatures. The general sequence is: - * preClose(), getDocumentBytes() and close(). - *

- * If calling preClose() dont't call PdfStamper.close(). - *

- * No external signatures are allowed if this methos is called. - * @throws IOException on error - * @throws DocumentException on error - */ - public void preClose() throws IOException, DocumentException { - preClose(null); - } - /** - * This is the first method to be called when using external signatures. The general sequence is: - * preClose(), getDocumentBytes() and close(). - *

- * If calling preClose() dont't call PdfStamper.close(). - *

- * If using an external signature exclusionSizes must contain at least - * the PdfName.CONTENTS key with the size that it will take in the - * document. Note that due to the hex string coding this size should be - * byte_size*2+2. - * @param exclusionSizes a HashMap with names and sizes to be excluded in the signature - * calculation. The key is a PdfName and the value an - * Integer. At least the PdfName.CONTENTS must be present - * @throws IOException on error - * @throws DocumentException on error - */ - public void preClose(HashMap exclusionSizes) throws IOException, DocumentException { - if (preClosed) - throw new DocumentException("Document already pre closed."); - preClosed = true; - AcroFields af = writer.getAcroFields(); - String name = getFieldName(); - boolean fieldExists = !(isInvisible() || isNewField()); - int flags = 132; - PdfIndirectReference refSig = writer.getPdfIndirectReference(); - if (fieldExists && name.indexOf('.') >= 0) { - ArrayList widgets = af.getFieldItem(name).widgets; - PdfDictionary widget = (PdfDictionary)widgets.get(0); - writer.markUsed(widget); - widget.put(PdfName.P, writer.getPageReference(getPage())); - widget.put(PdfName.V, refSig); - PdfDictionary ap = new PdfDictionary(); - ap.put(PdfName.N, getAppearance().getIndirectReference()); - widget.put(PdfName.AP, ap); - } - else { - if (fieldExists) { - flags = 0; - ArrayList merged = af.getFieldItem(name).merged; - PdfObject obj = PdfReader.getPdfObjectRelease(((PdfDictionary)merged.get(0)).get(PdfName.F)); - if (obj != null && obj.isNumber()) - flags = ((PdfNumber)obj).intValue(); - af.removeField(name); - } - writer.setSigFlags(3); - PdfFormField sigField = PdfFormField.createSignature(writer); - sigField.setFieldName(name); - sigField.put(PdfName.V, refSig); - sigField.setFlags(flags); - - int pagen = getPage(); - if (!isInvisible()) { - sigField.setWidget(getPageRect(), null); - sigField.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, getAppearance()); - } - else - sigField.setWidget(new Rectangle(0, 0), null); - sigField.setPage(pagen); - writer.addAnnotation(sigField, pagen); - } - - exclusionLocations = new HashMap(); - if (cryptoDictionary == null) { - if (PdfName.ADOBE_PPKLITE.equals(getFilter())) - sigStandard = new PdfSigGenericPKCS.PPKLite(getProvider()); - else if (PdfName.ADOBE_PPKMS.equals(getFilter())) - sigStandard = new PdfSigGenericPKCS.PPKMS(getProvider()); - else if (PdfName.VERISIGN_PPKVS.equals(getFilter())) - sigStandard = new PdfSigGenericPKCS.VeriSign(getProvider()); - else - throw new IllegalArgumentException("Unknown filter: " + getFilter()); - sigStandard.setExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); - if (getReason() != null) - sigStandard.setReason(getReason()); - if (getLocation() != null) - sigStandard.setLocation(getLocation()); - if (getContact() != null) - sigStandard.setContact(getContact()); - sigStandard.put(PdfName.M, new PdfDate(getSignDate())); - sigStandard.setSignInfo(getPrivKey(), getCertChain(), getCrlList()); - PdfString contents = (PdfString)sigStandard.get(PdfName.CONTENTS); - PdfLiteral lit = new PdfLiteral((contents.toString().length() + (PdfName.ADOBE_PPKLITE.equals(getFilter())?0:64)) * 2 + 2); - exclusionLocations.put(PdfName.CONTENTS, lit); - sigStandard.put(PdfName.CONTENTS, lit); - lit = new PdfLiteral(80); - exclusionLocations.put(PdfName.BYTERANGE, lit); - sigStandard.put(PdfName.BYTERANGE, lit); - if (certified) - addDocMDP(sigStandard); - if (signatureEvent != null) - signatureEvent.getSignatureDictionary(sigStandard); - writer.addToBody(sigStandard, refSig, false); - } - else { - PdfLiteral lit = new PdfLiteral(80); - exclusionLocations.put(PdfName.BYTERANGE, lit); - cryptoDictionary.put(PdfName.BYTERANGE, lit); - for (Iterator it = exclusionSizes.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry)it.next(); - PdfName key = (PdfName)entry.getKey(); - Integer v = (Integer)entry.getValue(); - lit = new PdfLiteral(v.intValue()); - exclusionLocations.put(key, lit); - cryptoDictionary.put(key, lit); - } - if (certified) - addDocMDP(cryptoDictionary); - if (signatureEvent != null) - signatureEvent.getSignatureDictionary(cryptoDictionary); - writer.addToBody(cryptoDictionary, refSig, false); - } - if (certified) { - // add DocMDP entry to root - PdfDictionary docmdp = new PdfDictionary(); - docmdp.put(new PdfName("DocMDP"), refSig); - writer.reader.getCatalog().put(new PdfName("Perms"), docmdp); - } - writer.close(stamper.getMoreInfo()); - - range = new int[exclusionLocations.size() * 2]; - int byteRangePosition = ((PdfLiteral)exclusionLocations.get(PdfName.BYTERANGE)).getPosition(); - exclusionLocations.remove(PdfName.BYTERANGE); - int idx = 1; - for (Iterator it = exclusionLocations.values().iterator(); it.hasNext();) { - PdfLiteral lit = (PdfLiteral)it.next(); - int n = lit.getPosition(); - range[idx++] = n; - range[idx++] = lit.getPosLength() + n; - } - Arrays.sort(range, 1, range.length - 1); - for (int k = 3; k < range.length - 2; k += 2) - range[k] -= range[k - 1]; - - if (tempFile == null) { - bout = sigout.getBuffer(); - boutLen = sigout.size(); - range[range.length - 1] = boutLen - range[range.length - 2]; - ByteBuffer bf = new ByteBuffer(); - bf.append('['); - for (int k = 0; k < range.length; ++k) - bf.append(range[k]).append(' '); - bf.append(']'); - System.arraycopy(bf.getBuffer(), 0, bout, byteRangePosition, bf.size()); - } - else { - try { - raf = new RandomAccessFile(tempFile, "rw"); - int boutLen = (int)raf.length(); - range[range.length - 1] = boutLen - range[range.length - 2]; - ByteBuffer bf = new ByteBuffer(); - bf.append('['); - for (int k = 0; k < range.length; ++k) - bf.append(range[k]).append(' '); - bf.append(']'); - raf.seek(byteRangePosition); - raf.write(bf.getBuffer(), 0, bf.size()); - } - catch (IOException e) { - try{raf.close();}catch(Exception ee){} - try{tempFile.delete();}catch(Exception ee){} - throw e; - } - } - } - - /** - * This is the last method to be called when using external signatures. The general sequence is: - * preClose(), getDocumentBytes() and close(). - *

- * update is a PdfDictionary that must have exactly the - * same keys as the ones provided in {@link #preClose(HashMap)}. - * @param update a PdfDictionary with the key/value that will fill the holes defined - * in {@link #preClose(HashMap)} - * @throws DocumentException on error - * @throws IOException on error - */ - public void close(PdfDictionary update) throws IOException, DocumentException { - try { - if (!preClosed) - throw new DocumentException("preClose() must be called first."); - ByteBuffer bf = new ByteBuffer(); - for (Iterator it = update.getKeys().iterator(); it.hasNext();) { - PdfName key = (PdfName)it.next(); - PdfObject obj = update.get(key); - PdfLiteral lit = (PdfLiteral)exclusionLocations.get(key); - if (lit == null) - throw new IllegalArgumentException("The key " + key.toString() + " didn't reserve space in preClose()."); - bf.reset(); - obj.toPdf(null, bf); - if (bf.size() > lit.getPosLength()) - throw new IllegalArgumentException("The key " + key.toString() + " is too big. Is " + bf.size() + ", reserved " + lit.getPosLength()); - if (tempFile == null) - System.arraycopy(bf.getBuffer(), 0, bout, lit.getPosition(), bf.size()); - else { - raf.seek(lit.getPosition()); - raf.write(bf.getBuffer(), 0, bf.size()); - } - } - if (update.size() != exclusionLocations.size()) - throw new IllegalArgumentException("The update dictionary has less keys than required."); - if (tempFile == null) { - originalout.write(bout, 0, boutLen); - } - else { - if (originalout != null) { - raf.seek(0); - int length = (int)raf.length(); - byte buf[] = new byte[8192]; - while (length > 0) { - int r = raf.read(buf, 0, Math.min(buf.length, length)); - if (r < 0) - throw new EOFException("Unexpected EOF"); - originalout.write(buf, 0, r); - length -= r; - } - } - } - } - finally { - if (tempFile != null) { - try{raf.close();}catch(Exception ee){} - if (originalout != null) - try{tempFile.delete();}catch(Exception ee){} - } - if (originalout != null) - try{originalout.close();}catch(Exception e){} - } - } - - private void addDocMDP(PdfDictionary crypto) { - PdfDictionary reference = new PdfDictionary(); - PdfDictionary transformParams = new PdfDictionary(); - transformParams.put(PdfName.P, new PdfNumber(1)); - transformParams.put(PdfName.V, new PdfName("1.2")); - transformParams.put(PdfName.TYPE, new PdfName("TransformParams")); - reference.put(new PdfName("TransformMethod"), new PdfName("DocMDP")); - reference.put(PdfName.TYPE, new PdfName("SigRef")); - reference.put(new PdfName("TransformParams"), transformParams); - PdfArray types = new PdfArray(); - types.add(reference); - crypto.put(new PdfName("Reference"), types); - } - - private static int indexArray(byte bout[], int position, String search) { - byte ss[] = PdfEncodings.convertToBytes(search, null); - while (true) { - int k; - for (k = 0; k < ss.length; ++k) { - if (ss[k] != bout[position + k]) - break; - } - if (k == ss.length) - return position; - ++position; - } - } - - private static int indexFile(RandomAccessFile raf, int position, String search) throws IOException { - byte ss[] = PdfEncodings.convertToBytes(search, null); - while (true) { - raf.seek(position); - int k; - for (k = 0; k < ss.length; ++k) { - int b = raf.read(); - if (b < 0) - throw new EOFException("Unexpected EOF"); - if (ss[k] != (byte)b) - break; - } - if (k == ss.length) - return position; - ++position; - } - } - - /** - * Gets the document bytes that are hashable when using external signatures. The general sequence is: - * preClose(), getRangeStream() and close(). - *

- * @return the document bytes that are hashable - */ - public InputStream getRangeStream() { - return new PdfSignatureAppearance.RangeStream(raf, bout, range); - } - - /** - * Gets the user made signature dictionary. This is the dictionary at the /V key. - * @return the user made signature dictionary - */ - public com.lowagie.text.pdf.PdfDictionary getCryptoDictionary() { - return cryptoDictionary; - } - - /** - * Sets a user made signature dictionary. This is the dictionary at the /V key. - * @param cryptoDictionary a user made signature dictionary - */ - public void setCryptoDictionary(com.lowagie.text.pdf.PdfDictionary cryptoDictionary) { - this.cryptoDictionary = cryptoDictionary; - } - - /** - * Gets the PdfStamper associated with this instance. - * @return the PdfStamper associated with this instance - */ - public com.lowagie.text.pdf.PdfStamper getStamper() { - return stamper; - } - - void setStamper(com.lowagie.text.pdf.PdfStamper stamper) { - this.stamper = stamper; - } - - /** - * Checks if the document is in the process of closing. - * @return true if the document is in the process of closing, - * false otherwise - */ - public boolean isPreClosed() { - return preClosed; - } - - /** - * Gets the instance of the standard signature dictionary. This instance - * is only available after pre close. - *

- * The main use is to insert external signatures. - * @return the instance of the standard signature dictionary - */ - public com.lowagie.text.pdf.PdfSigGenericPKCS getSigStandard() { - return sigStandard; - } - - /** - * Gets the signing contact. - * @return the signing contact - */ - public String getContact() { - return this.contact; - } - - /** - * Sets the signing contact. - * @param contact the signing contact - */ - public void setContact(String contact) { - this.contact = contact; - } - - /** - * Gets the n2 and n4 layer font. - * @return the n2 and n4 layer font - */ - public Font getLayer2Font() { - return this.layer2Font; - } - - /** - * Sets the n2 and n4 layer font. If the font size is zero, auto-fit will be used. - * @param layer2Font the n2 and n4 font - */ - public void setLayer2Font(Font layer2Font) { - this.layer2Font = layer2Font; - } - - /** - * Gets the Acrobat 6.0 layer mode. - * @return the Acrobat 6.0 layer mode - */ - public boolean isAcro6Layers() { - return this.acro6Layers; - } - - /** - * Acrobat 6.0 and higher recomends that only layer n2 and n4 be present. This method sets that mode. - * @param acro6Layers if true only the layers n2 and n4 will be present - */ - public void setAcro6Layers(boolean acro6Layers) { - this.acro6Layers = acro6Layers; - } - - /** Sets the run direction in the n2 and n4 layer. - * @param runDirection the run direction - */ - public void setRunDirection(int runDirection) { - if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT || runDirection > PdfWriter.RUN_DIRECTION_RTL) - throw new RuntimeException("Invalid run direction: " + runDirection); - this.runDirection = runDirection; - } - - /** Gets the run direction. - * @return the run direction - */ - public int getRunDirection() { - return runDirection; - } - - /** - * Getter for property signatureEvent. - * @return Value of property signatureEvent. - */ - public SignatureEvent getSignatureEvent() { - return this.signatureEvent; - } - - /** - * Sets the signature event to allow modification of the signature dictionary. - * @param signatureEvent the signature event - */ - public void setSignatureEvent(SignatureEvent signatureEvent) { - this.signatureEvent = signatureEvent; - } - - /** - * Gets the background image for the layer 2. - * @return the background image for the layer 2 - */ - public Image getImage() { - return this.image; - } - - /** - * Sets the background image for the layer 2. - * @param image the background image for the layer 2 - */ - public void setImage(Image image) { - this.image = image; - } - - /** - * Gets the scaling to be applied to the background image. - * @return the scaling to be applied to the background image - */ - public float getImageScale() { - return this.imageScale; - } - - /** - * Sets the scaling to be applied to the background image. If it's zero the image - * will fully fill the rectangle. If it's less than zero the image will fill the rectangle but - * will keep the proportions. If it's greater than zero that scaling will be applied. - * In any of the cases the image will always be centered. It's zero by default. - * @param imageScale the scaling to be applied to the background image - */ - public void setImageScale(float imageScale) { - this.imageScale = imageScale; - } - - /** - * Commands to draw a yellow question mark in a stream content - */ - public static final String questionMark = - "% DSUnknown\n" + - "q\n" + - "1 G\n" + - "1 g\n" + - "0.1 0 0 0.1 9 0 cm\n" + - "0 J 0 j 4 M []0 d\n" + - "1 i \n" + - "0 g\n" + - "313 292 m\n" + - "313 404 325 453 432 529 c\n" + - "478 561 504 597 504 645 c\n" + - "504 736 440 760 391 760 c\n" + - "286 760 271 681 265 626 c\n" + - "265 625 l\n" + - "100 625 l\n" + - "100 828 253 898 381 898 c\n" + - "451 898 679 878 679 650 c\n" + - "679 555 628 499 538 435 c\n" + - "488 399 467 376 467 292 c\n" + - "313 292 l\n" + - "h\n" + - "308 214 170 -164 re\n" + - "f\n" + - "0.44 G\n" + - "1.2 w\n" + - "1 1 0.4 rg\n" + - "287 318 m\n" + - "287 430 299 479 406 555 c\n" + - "451 587 478 623 478 671 c\n" + - "478 762 414 786 365 786 c\n" + - "260 786 245 707 239 652 c\n" + - "239 651 l\n" + - "74 651 l\n" + - "74 854 227 924 355 924 c\n" + - "425 924 653 904 653 676 c\n" + - "653 581 602 525 512 461 c\n" + - "462 425 441 402 441 318 c\n" + - "287 318 l\n" + - "h\n" + - "282 240 170 -164 re\n" + - "B\n" + - "Q\n"; - - /** - * Holds value of property contact. - */ - private String contact; - - /** - * Holds value of property layer2Font. - */ - private Font layer2Font; - - /** - * Holds value of property layer4Text. - */ - private String layer4Text; - - /** - * Holds value of property acro6Layers. - */ - private boolean acro6Layers; - - /** - * Holds value of property runDirection. - */ - private int runDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; - - /** - * Holds value of property signatureEvent. - */ - private SignatureEvent signatureEvent; - - /** - * Holds value of property image. - */ - private Image image; - - /** - * Holds value of property imageScale. - */ - private float imageScale; - - /** - * - */ - private static class RangeStream extends InputStream { - private byte b[] = new byte[1]; - private RandomAccessFile raf; - private byte bout[]; - private int range[]; - private int rangePosition = 0; - - private RangeStream(RandomAccessFile raf, byte bout[], int range[]) { - this.raf = raf; - this.bout = bout; - this.range = range; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - int n = read(b); - if (n != 1) - return -1; - return b[0] & 0xff; - } - - /** - * @see java.io.InputStream#read(byte[], int, int) - */ - public int read(byte[] b, int off, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - if (rangePosition >= range[range.length - 2] + range[range.length - 1]) { - return -1; - } - for (int k = 0; k < range.length; k += 2) { - int start = range[k]; - int end = start + range[k + 1]; - if (rangePosition < start) - rangePosition = start; - if (rangePosition >= start && rangePosition < end) { - int lenf = Math.min(len, end - rangePosition); - if (raf == null) - System.arraycopy(bout, rangePosition, b, off, lenf); - else { - raf.seek(rangePosition); - raf.readFully(b, off, lenf); - } - rangePosition += lenf; - return lenf; - } - } - return -1; - } - } - - /** - * An interface to retrieve the signature dictionary for modification. - */ - public interface SignatureEvent { - /** - * Allows modification of the signature dictionary. - * @param sig the signature dictionary - */ - public void getSignatureDictionary(PdfDictionary sig); - } - - /** - * Holds value of property certified. - */ - private boolean certified; - - /** - * Gets the certified status of this document. - * @return the certified status - */ - public boolean isCertified() { - return this.certified; - } - - /** - * Sets the document type to certified instead of simply signed. The certified document doesn't allow any changes. - * @param certified true to certify the document, false to just apply a simple signature - */ - public void setCertified(boolean certified) { - this.certified = certified; - } -} -- cgit v1.2.3