Source Code Cross Referenced for PdfSignatureAppearance.java in  » PDF » pdf-itext » com » lowagie » text » pdf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » pdf itext » com.lowagie.text.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: PdfSignatureAppearance.java 2752 2007-05-15 14:58:33Z blowagie $
0003:         *
0004:         * Copyright 2004-2006 by Paulo Soares.
0005:         *
0006:         * The contents of this file are subject to the Mozilla Public License Version 1.1
0007:         * (the "License"); you may not use this file except in compliance with the License.
0008:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0009:         *
0010:         * Software distributed under the License is distributed on an "AS IS" basis,
0011:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012:         * for the specific language governing rights and limitations under the License.
0013:         *
0014:         * The Original Code is 'iText, a free JAVA-PDF library'.
0015:         *
0016:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0017:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0018:         * All Rights Reserved.
0019:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0020:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0021:         *
0022:         * Contributor(s): all the names of the contributors are added in the source code
0023:         * where applicable.
0024:         *
0025:         * Alternatively, the contents of this file may be used under the terms of the
0026:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0027:         * provisions of LGPL are applicable instead of those above.  If you wish to
0028:         * allow use of your version of this file only under the terms of the LGPL
0029:         * License and not to allow others to use your version of this file under
0030:         * the MPL, indicate your decision by deleting the provisions above and
0031:         * replace them with the notice and other provisions required by the LGPL.
0032:         * If you do not delete the provisions above, a recipient may use your version
0033:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0034:         *
0035:         * This library is free software; you can redistribute it and/or modify it
0036:         * under the terms of the MPL as stated above or under the terms of the GNU
0037:         * Library General Public License as published by the Free Software Foundation;
0038:         * either version 2 of the License, or any later version.
0039:         *
0040:         * This library is distributed in the hope that it will be useful, but WITHOUT
0041:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0042:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0043:         * details.
0044:         *
0045:         * If you didn't download this code from the following link, you should check if
0046:         * you aren't using an obsolete version:
0047:         * http://www.lowagie.com/iText/
0048:         */
0049:        package com.lowagie.text.pdf;
0050:
0051:        import java.io.EOFException;
0052:        import java.io.File;
0053:        import java.io.IOException;
0054:        import java.io.InputStream;
0055:        import java.io.OutputStream;
0056:        import java.io.RandomAccessFile;
0057:        import java.security.PrivateKey;
0058:        import java.security.cert.CRL;
0059:        import java.security.cert.Certificate;
0060:        import java.security.cert.X509Certificate;
0061:        import java.text.SimpleDateFormat;
0062:        import java.util.ArrayList;
0063:        import java.util.Arrays;
0064:        import java.util.Calendar;
0065:        import java.util.GregorianCalendar;
0066:        import java.util.HashMap;
0067:        import java.util.Iterator;
0068:        import java.util.Map;
0069:
0070:        import com.lowagie.text.Chunk;
0071:        import com.lowagie.text.DocumentException;
0072:        import com.lowagie.text.Element;
0073:        import com.lowagie.text.ExceptionConverter;
0074:        import com.lowagie.text.Font;
0075:        import com.lowagie.text.Image;
0076:        import com.lowagie.text.Paragraph;
0077:        import com.lowagie.text.Phrase;
0078:        import com.lowagie.text.Rectangle;
0079:
0080:        /**
0081:         * This class takes care of the cryptographic options and appearances that form a signature.
0082:         */
0083:        public class PdfSignatureAppearance {
0084:
0085:            /**
0086:             * The rendering mode is just the description
0087:             */
0088:            public static final int SignatureRenderDescription = 0;
0089:            /**
0090:             * The rendering mode is the name of the signer and the description
0091:             */
0092:            public static final int SignatureRenderNameAndDescription = 1;
0093:            /**
0094:             * The rendering mode is an image and the description
0095:             */
0096:            public static final int SignatureRenderGraphicAndDescription = 2;
0097:
0098:            /**
0099:             * The self signed filter.
0100:             */
0101:            public static final PdfName SELF_SIGNED = PdfName.ADOBE_PPKLITE;
0102:            /**
0103:             * The VeriSign filter.
0104:             */
0105:            public static final PdfName VERISIGN_SIGNED = PdfName.VERISIGN_PPKVS;
0106:            /**
0107:             * The Windows Certificate Security.
0108:             */
0109:            public static final PdfName WINCER_SIGNED = PdfName.ADOBE_PPKMS;
0110:
0111:            public static final int NOT_CERTIFIED = 0;
0112:            public static final int CERTIFIED_NO_CHANGES_ALLOWED = 1;
0113:            public static final int CERTIFIED_FORM_FILLING = 2;
0114:            public static final int CERTIFIED_FORM_FILLING_AND_ANNOTATIONS = 3;
0115:
0116:            private static final float TOP_SECTION = 0.3f;
0117:            private static final float MARGIN = 2;
0118:            private Rectangle rect;
0119:            private Rectangle pageRect;
0120:            private PdfTemplate app[] = new PdfTemplate[5];
0121:            private PdfTemplate frm;
0122:            private PdfStamperImp writer;
0123:            private String layer2Text;
0124:            private String reason;
0125:            private String location;
0126:            private Calendar signDate;
0127:            private String provider;
0128:            private int page = 1;
0129:            private String fieldName;
0130:            private PrivateKey privKey;
0131:            private Certificate[] certChain;
0132:            private CRL[] crlList;
0133:            private PdfName filter;
0134:            private boolean newField;
0135:            private ByteBuffer sigout;
0136:            private OutputStream originalout;
0137:            private File tempFile;
0138:            private PdfDictionary cryptoDictionary;
0139:            private PdfStamper stamper;
0140:            private boolean preClosed = false;
0141:            private PdfSigGenericPKCS sigStandard;
0142:            private int range[];
0143:            private RandomAccessFile raf;
0144:            private byte bout[];
0145:            private int boutLen;
0146:            private byte externalDigest[];
0147:            private byte externalRSAdata[];
0148:            private String digestEncryptionAlgorithm;
0149:            private HashMap exclusionLocations;
0150:
0151:            PdfSignatureAppearance(PdfStamperImp writer) {
0152:                this .writer = writer;
0153:                signDate = new GregorianCalendar();
0154:                fieldName = getNewSigName();
0155:            }
0156:
0157:            private int render = SignatureRenderDescription;
0158:
0159:            /**
0160:             * Gets the rendering mode for this signature.
0161:             * @return the rendering mode for this signature
0162:             */
0163:            public int getRender() {
0164:                return render;
0165:            }
0166:
0167:            /**
0168:             * Sets the rendering mode for this signature.
0169:             * The rendering modes can be the constants <CODE>SignatureRenderDescription</CODE>,
0170:             * <CODE>SignatureRenderNameAndDescription</CODE> or <CODE>SignatureRenderGraphicAndDescription</CODE>.
0171:             * The two last modes should be used with Acrobat 6 layer type.
0172:             * @param render the render mode
0173:             */
0174:            public void setRender(int render) {
0175:                this .render = render;
0176:            }
0177:
0178:            private Image signatureGraphic = null;
0179:
0180:            /**
0181:             * Gets the Image object to render.
0182:             * @return the image
0183:             */
0184:            public Image getSignatureGraphic() {
0185:                return signatureGraphic;
0186:            }
0187:
0188:            /**
0189:             * Sets the Image object to render when Render is set to <CODE>SignatureRenderGraphicAndDescription</CODE>
0190:             * @param signatureGraphic image rendered. If <CODE>null</CODE> the mode is defaulted
0191:             * to <CODE>SignatureRenderDescription</CODE>
0192:             */
0193:            public void setSignatureGraphic(Image signatureGraphic) {
0194:                this .signatureGraphic = signatureGraphic;
0195:            }
0196:
0197:            /**
0198:             * Sets the signature text identifying the signer.
0199:             * @param text the signature text identifying the signer. If <CODE>null</CODE> or not set
0200:             * a standard description will be used
0201:             */
0202:            public void setLayer2Text(String text) {
0203:                layer2Text = text;
0204:            }
0205:
0206:            /**
0207:             * Gets the signature text identifying the signer if set by setLayer2Text().
0208:             * @return the signature text identifying the signer
0209:             */
0210:            public String getLayer2Text() {
0211:                return layer2Text;
0212:            }
0213:
0214:            /**
0215:             * Sets the text identifying the signature status.
0216:             * @param text the text identifying the signature status. If <CODE>null</CODE> or not set
0217:             * the description "Signature Not Verified" will be used
0218:             */
0219:            public void setLayer4Text(String text) {
0220:                layer4Text = text;
0221:            }
0222:
0223:            /**
0224:             * Gets the text identifying the signature status if set by setLayer4Text().
0225:             * @return the text identifying the signature status
0226:             */
0227:            public String getLayer4Text() {
0228:                return layer4Text;
0229:            }
0230:
0231:            /**
0232:             * Gets the rectangle representing the signature dimensions.
0233:             * @return the rectangle representing the signature dimensions. It may be <CODE>null</CODE>
0234:             * or have zero width or height for invisible signatures
0235:             */
0236:            public Rectangle getRect() {
0237:                return rect;
0238:            }
0239:
0240:            /**
0241:             * Gets the visibility status of the signature.
0242:             * @return the visibility status of the signature
0243:             */
0244:            public boolean isInvisible() {
0245:                return (rect == null || rect.getWidth() == 0 || rect
0246:                        .getHeight() == 0);
0247:            }
0248:
0249:            /**
0250:             * Sets the cryptographic parameters.
0251:             * @param privKey the private key
0252:             * @param certChain the certificate chain
0253:             * @param crlList the certificate revocation list. It may be <CODE>null</CODE>
0254:             * @param filter the crytographic filter type. It can be SELF_SIGNED, VERISIGN_SIGNED or WINCER_SIGNED
0255:             */
0256:            public void setCrypto(PrivateKey privKey, Certificate[] certChain,
0257:                    CRL[] crlList, PdfName filter) {
0258:                this .privKey = privKey;
0259:                this .certChain = certChain;
0260:                this .crlList = crlList;
0261:                this .filter = filter;
0262:            }
0263:
0264:            /**
0265:             * Sets the signature to be visible. It creates a new visible signature field.
0266:             * @param pageRect the position and dimension of the field in the page
0267:             * @param page the page to place the field. The fist page is 1
0268:             * @param fieldName the field name or <CODE>null</CODE> to generate automatically a new field name
0269:             */
0270:            public void setVisibleSignature(Rectangle pageRect, int page,
0271:                    String fieldName) {
0272:                if (fieldName != null) {
0273:                    if (fieldName.indexOf('.') >= 0)
0274:                        throw new IllegalArgumentException(
0275:                                "Field names cannot contain a dot.");
0276:                    AcroFields af = writer.getAcroFields();
0277:                    AcroFields.Item item = af.getFieldItem(fieldName);
0278:                    if (item != null)
0279:                        throw new IllegalArgumentException("The field "
0280:                                + fieldName + " already exists.");
0281:                    this .fieldName = fieldName;
0282:                }
0283:                if (page < 1 || page > writer.reader.getNumberOfPages())
0284:                    throw new IllegalArgumentException("Invalid page number: "
0285:                            + page);
0286:                this .pageRect = new Rectangle(pageRect);
0287:                this .pageRect.normalize();
0288:                rect = new Rectangle(this .pageRect.getWidth(), this .pageRect
0289:                        .getHeight());
0290:                this .page = page;
0291:                newField = true;
0292:            }
0293:
0294:            /**
0295:             * Sets the signature to be visible. An empty signature field with the same name must already exist.
0296:             * @param fieldName the existing empty signature field name
0297:             */
0298:            public void setVisibleSignature(String fieldName) {
0299:                AcroFields af = writer.getAcroFields();
0300:                AcroFields.Item item = af.getFieldItem(fieldName);
0301:                if (item == null)
0302:                    throw new IllegalArgumentException("The field " + fieldName
0303:                            + " does not exist.");
0304:                PdfDictionary merged = (PdfDictionary) item.merged.get(0);
0305:                if (!PdfName.SIG.equals(PdfReader.getPdfObject(merged
0306:                        .get(PdfName.FT))))
0307:                    throw new IllegalArgumentException("The field " + fieldName
0308:                            + " is not a signature field.");
0309:                this .fieldName = fieldName;
0310:                PdfArray r = (PdfArray) PdfReader.getPdfObject(merged
0311:                        .get(PdfName.RECT));
0312:                ArrayList ar = r.getArrayList();
0313:                float llx = ((PdfNumber) PdfReader.getPdfObject((PdfObject) ar
0314:                        .get(0))).floatValue();
0315:                float lly = ((PdfNumber) PdfReader.getPdfObject((PdfObject) ar
0316:                        .get(1))).floatValue();
0317:                float urx = ((PdfNumber) PdfReader.getPdfObject((PdfObject) ar
0318:                        .get(2))).floatValue();
0319:                float ury = ((PdfNumber) PdfReader.getPdfObject((PdfObject) ar
0320:                        .get(3))).floatValue();
0321:                pageRect = new Rectangle(llx, lly, urx, ury);
0322:                pageRect.normalize();
0323:                page = ((Integer) item.page.get(0)).intValue();
0324:                int rotation = writer.reader.getPageRotation(page);
0325:                Rectangle pageSize = writer.reader
0326:                        .getPageSizeWithRotation(page);
0327:                switch (rotation) {
0328:                case 90:
0329:                    pageRect = new Rectangle(pageRect.getBottom(), pageSize
0330:                            .getTop()
0331:                            - pageRect.getLeft(), pageRect.getTop(), pageSize
0332:                            .getTop()
0333:                            - pageRect.getRight());
0334:                    break;
0335:                case 180:
0336:                    pageRect = new Rectangle(pageSize.getRight()
0337:                            - pageRect.getLeft(), pageSize.getTop()
0338:                            - pageRect.getBottom(), pageSize.getRight()
0339:                            - pageRect.getRight(), pageSize.getTop()
0340:                            - pageRect.getTop());
0341:                    break;
0342:                case 270:
0343:                    pageRect = new Rectangle(pageSize.getRight()
0344:                            - pageRect.getBottom(), pageRect.getLeft(),
0345:                            pageSize.getRight() - pageRect.getTop(), pageRect
0346:                                    .getRight());
0347:                    break;
0348:                }
0349:                if (rotation != 0)
0350:                    pageRect.normalize();
0351:                rect = new Rectangle(this .pageRect.getWidth(), this .pageRect
0352:                        .getHeight());
0353:            }
0354:
0355:            /**
0356:             * Gets a template layer to create a signature appearance. The layers can go from 0 to 4.
0357:             * <p>
0358:             * Consult <A HREF="http://partners.adobe.com/asn/developer/pdfs/tn/PPKAppearances.pdf">PPKAppearances.pdf</A>
0359:             * for further details.
0360:             * @param layer the layer
0361:             * @return a template
0362:             */
0363:            public PdfTemplate getLayer(int layer) {
0364:                if (layer < 0 || layer >= app.length)
0365:                    return null;
0366:                PdfTemplate t = app[layer];
0367:                if (t == null) {
0368:                    t = app[layer] = new PdfTemplate(writer);
0369:                    t.setBoundingBox(rect);
0370:                    writer.addDirectTemplateSimple(t, new PdfName("n" + layer));
0371:                }
0372:                return t;
0373:            }
0374:
0375:            /**
0376:             * Gets the template that aggregates all appearance layers. This corresponds to the /FRM resource.
0377:             * <p>
0378:             * Consult <A HREF="http://partners.adobe.com/asn/developer/pdfs/tn/PPKAppearances.pdf">PPKAppearances.pdf</A>
0379:             * for further details.
0380:             * @return the template that aggregates all appearance layers
0381:             */
0382:            public PdfTemplate getTopLayer() {
0383:                if (frm == null) {
0384:                    frm = new PdfTemplate(writer);
0385:                    frm.setBoundingBox(rect);
0386:                    writer.addDirectTemplateSimple(frm, new PdfName("FRM"));
0387:                }
0388:                return frm;
0389:            }
0390:
0391:            /**
0392:             * Gets the main appearance layer.
0393:             * <p>
0394:             * Consult <A HREF="http://partners.adobe.com/asn/developer/pdfs/tn/PPKAppearances.pdf">PPKAppearances.pdf</A>
0395:             * for further details.
0396:             * @return the main appearance layer
0397:             * @throws DocumentException on error
0398:             */
0399:            public PdfTemplate getAppearance() throws DocumentException {
0400:                if (isInvisible()) {
0401:                    PdfTemplate t = new PdfTemplate(writer);
0402:                    t.setBoundingBox(new Rectangle(0, 0));
0403:                    writer.addDirectTemplateSimple(t, null);
0404:                    return t;
0405:                }
0406:                if (app[0] == null) {
0407:                    PdfTemplate t = app[0] = new PdfTemplate(writer);
0408:                    t.setBoundingBox(new Rectangle(100, 100));
0409:                    writer.addDirectTemplateSimple(t, new PdfName("n0"));
0410:                    t.setLiteral("% DSBlank\n");
0411:                }
0412:                if (app[1] == null && !acro6Layers) {
0413:                    PdfTemplate t = app[1] = new PdfTemplate(writer);
0414:                    t.setBoundingBox(new Rectangle(100, 100));
0415:                    writer.addDirectTemplateSimple(t, new PdfName("n1"));
0416:                    t.setLiteral(questionMark);
0417:                }
0418:                if (app[2] == null) {
0419:                    String text;
0420:                    if (layer2Text == null) {
0421:                        StringBuffer buf = new StringBuffer();
0422:                        buf.append("Digitally signed by ").append(
0423:                                PdfPKCS7.getSubjectFields(
0424:                                        (X509Certificate) certChain[0])
0425:                                        .getField("CN")).append('\n');
0426:                        SimpleDateFormat sd = new SimpleDateFormat(
0427:                                "yyyy.MM.dd HH:mm:ss z");
0428:                        buf.append("Date: ").append(
0429:                                sd.format(signDate.getTime()));
0430:                        if (reason != null)
0431:                            buf.append('\n').append("Reason: ").append(reason);
0432:                        if (location != null)
0433:                            buf.append('\n').append("Location: ").append(
0434:                                    location);
0435:                        text = buf.toString();
0436:                    } else
0437:                        text = layer2Text;
0438:                    PdfTemplate t = app[2] = new PdfTemplate(writer);
0439:                    t.setBoundingBox(rect);
0440:                    writer.addDirectTemplateSimple(t, new PdfName("n2"));
0441:                    if (image != null) {
0442:                        if (imageScale == 0) {
0443:                            t.addImage(image, rect.getWidth(), 0, 0, rect
0444:                                    .getHeight(), 0, 0);
0445:                        } else {
0446:                            float usableScale = imageScale;
0447:                            if (imageScale < 0)
0448:                                usableScale = Math.min(rect.getWidth()
0449:                                        / image.getWidth(), rect.getHeight()
0450:                                        / image.getHeight());
0451:                            float w = image.getWidth() * usableScale;
0452:                            float h = image.getHeight() * usableScale;
0453:                            float x = (rect.getWidth() - w) / 2;
0454:                            float y = (rect.getHeight() - h) / 2;
0455:                            t.addImage(image, w, 0, 0, h, x, y);
0456:                        }
0457:                    }
0458:                    Font font;
0459:                    if (layer2Font == null)
0460:                        font = new Font();
0461:                    else
0462:                        font = new Font(layer2Font);
0463:                    float size = font.getSize();
0464:
0465:                    Rectangle dataRect = null;
0466:                    Rectangle signatureRect = null;
0467:
0468:                    if (render == SignatureRenderNameAndDescription
0469:                            || (render == SignatureRenderGraphicAndDescription && this .signatureGraphic != null)) {
0470:                        // origin is the bottom-left
0471:                        signatureRect = new Rectangle(MARGIN, MARGIN, rect
0472:                                .getWidth()
0473:                                / 2 - MARGIN, rect.getHeight() - MARGIN);
0474:                        dataRect = new Rectangle(rect.getWidth() / 2 + MARGIN
0475:                                / 2, MARGIN, rect.getWidth() - MARGIN / 2, rect
0476:                                .getHeight()
0477:                                - MARGIN);
0478:
0479:                        if (rect.getHeight() > rect.getWidth()) {
0480:                            signatureRect = new Rectangle(MARGIN, rect
0481:                                    .getHeight() / 2, rect.getWidth() - MARGIN,
0482:                                    rect.getHeight());
0483:                            dataRect = new Rectangle(MARGIN, MARGIN, rect
0484:                                    .getWidth()
0485:                                    - MARGIN, rect.getHeight() / 2 - MARGIN);
0486:                        }
0487:                    } else {
0488:                        dataRect = new Rectangle(MARGIN, MARGIN, rect
0489:                                .getWidth()
0490:                                - MARGIN, rect.getHeight() * (1 - TOP_SECTION)
0491:                                - MARGIN);
0492:                    }
0493:
0494:                    if (render == SignatureRenderNameAndDescription) {
0495:                        String signedBy = PdfPKCS7.getSubjectFields(
0496:                                (X509Certificate) certChain[0]).getField("CN");
0497:                        Rectangle sr2 = new Rectangle(signatureRect.getWidth()
0498:                                - MARGIN, signatureRect.getHeight() - MARGIN);
0499:                        float signedSize = fitText(font, signedBy, sr2, -1,
0500:                                runDirection);
0501:
0502:                        ColumnText ct2 = new ColumnText(t);
0503:                        ct2.setRunDirection(runDirection);
0504:                        ct2.setSimpleColumn(new Phrase(signedBy, font),
0505:                                signatureRect.getLeft(), signatureRect
0506:                                        .getBottom(), signatureRect.getRight(),
0507:                                signatureRect.getTop(), signedSize,
0508:                                Element.ALIGN_LEFT);
0509:
0510:                        ct2.go();
0511:                    } else if (render == SignatureRenderGraphicAndDescription) {
0512:                        ColumnText ct2 = new ColumnText(t);
0513:                        ct2.setRunDirection(runDirection);
0514:                        ct2.setSimpleColumn(signatureRect.getLeft(),
0515:                                signatureRect.getBottom(), signatureRect
0516:                                        .getRight(), signatureRect.getTop(), 0,
0517:                                Element.ALIGN_RIGHT);
0518:
0519:                        Image im = Image.getInstance(signatureGraphic);
0520:                        im.scaleToFit(signatureRect.getWidth(), signatureRect
0521:                                .getHeight());
0522:
0523:                        Paragraph p = new Paragraph();
0524:                        // must calculate the point to draw from to make image appear in middle of column
0525:                        float x = 0;
0526:                        // experimentation found this magic number to counteract Adobe's signature graphic, which
0527:                        // offsets the y co-ordinate by 15 units
0528:                        float y = -im.getScaledHeight() + 15;
0529:
0530:                        x = x
0531:                                + (signatureRect.getWidth() - im
0532:                                        .getScaledWidth()) / 2;
0533:                        y = y
0534:                                - (signatureRect.getHeight() - im
0535:                                        .getScaledHeight()) / 2;
0536:                        p.add(new Chunk(im, x
0537:                                + (signatureRect.getWidth() - im
0538:                                        .getScaledWidth()) / 2, y, false));
0539:                        ct2.addElement(p);
0540:                        ct2.go();
0541:                    }
0542:
0543:                    if (size <= 0) {
0544:                        Rectangle sr = new Rectangle(dataRect.getWidth(),
0545:                                dataRect.getHeight());
0546:                        size = fitText(font, text, sr, 12, runDirection);
0547:                    }
0548:                    ColumnText ct = new ColumnText(t);
0549:                    ct.setRunDirection(runDirection);
0550:                    ct.setSimpleColumn(new Phrase(text, font), dataRect
0551:                            .getLeft(), dataRect.getBottom(), dataRect
0552:                            .getRight(), dataRect.getTop(), size,
0553:                            Element.ALIGN_LEFT);
0554:                    ct.go();
0555:                }
0556:                if (app[3] == null && !acro6Layers) {
0557:                    PdfTemplate t = app[3] = new PdfTemplate(writer);
0558:                    t.setBoundingBox(new Rectangle(100, 100));
0559:                    writer.addDirectTemplateSimple(t, new PdfName("n3"));
0560:                    t.setLiteral("% DSBlank\n");
0561:                }
0562:                if (app[4] == null && !acro6Layers) {
0563:                    PdfTemplate t = app[4] = new PdfTemplate(writer);
0564:                    t
0565:                            .setBoundingBox(new Rectangle(0, rect.getHeight()
0566:                                    * (1 - TOP_SECTION), rect.getRight(), rect
0567:                                    .getTop()));
0568:                    writer.addDirectTemplateSimple(t, new PdfName("n4"));
0569:                    Font font;
0570:                    if (layer2Font == null)
0571:                        font = new Font();
0572:                    else
0573:                        font = new Font(layer2Font);
0574:                    float size = font.getSize();
0575:                    String text = "Signature Not Verified";
0576:                    if (layer4Text != null)
0577:                        text = layer4Text;
0578:                    Rectangle sr = new Rectangle(rect.getWidth() - 2 * MARGIN,
0579:                            rect.getHeight() * TOP_SECTION - 2 * MARGIN);
0580:                    size = fitText(font, text, sr, 15, runDirection);
0581:                    ColumnText ct = new ColumnText(t);
0582:                    ct.setRunDirection(runDirection);
0583:                    ct.setSimpleColumn(new Phrase(text, font), MARGIN, 0, rect
0584:                            .getWidth()
0585:                            - MARGIN, rect.getHeight() - MARGIN, size,
0586:                            Element.ALIGN_LEFT);
0587:                    ct.go();
0588:                }
0589:                int rotation = writer.reader.getPageRotation(page);
0590:                Rectangle rotated = new Rectangle(rect);
0591:                int n = rotation;
0592:                while (n > 0) {
0593:                    rotated = rotated.rotate();
0594:                    n -= 90;
0595:                }
0596:                if (frm == null) {
0597:                    frm = new PdfTemplate(writer);
0598:                    frm.setBoundingBox(rotated);
0599:                    writer.addDirectTemplateSimple(frm, new PdfName("FRM"));
0600:                    float scale = Math.min(rect.getWidth(), rect.getHeight()) * 0.9f;
0601:                    float x = (rect.getWidth() - scale) / 2;
0602:                    float y = (rect.getHeight() - scale) / 2;
0603:                    scale /= 100;
0604:                    if (rotation == 90)
0605:                        frm.concatCTM(0, 1, -1, 0, rect.getHeight(), 0);
0606:                    else if (rotation == 180)
0607:                        frm.concatCTM(-1, 0, 0, -1, rect.getWidth(), rect
0608:                                .getHeight());
0609:                    else if (rotation == 270)
0610:                        frm.concatCTM(0, -1, 1, 0, 0, rect.getWidth());
0611:                    frm.addTemplate(app[0], 0, 0);
0612:                    if (!acro6Layers)
0613:                        frm.addTemplate(app[1], scale, 0, 0, scale, x, y);
0614:                    frm.addTemplate(app[2], 0, 0);
0615:                    if (!acro6Layers) {
0616:                        frm.addTemplate(app[3], scale, 0, 0, scale, x, y);
0617:                        frm.addTemplate(app[4], 0, 0);
0618:                    }
0619:                }
0620:                PdfTemplate napp = new PdfTemplate(writer);
0621:                napp.setBoundingBox(rotated);
0622:                writer.addDirectTemplateSimple(napp, null);
0623:                napp.addTemplate(frm, 0, 0);
0624:                return napp;
0625:            }
0626:
0627:            /**
0628:             * Fits the text to some rectangle adjusting the font size as needed.
0629:             * @param font the font to use
0630:             * @param text the text
0631:             * @param rect the rectangle where the text must fit
0632:             * @param maxFontSize the maximum font size
0633:             * @param runDirection the run direction
0634:             * @return the calculated font size that makes the text fit
0635:             */
0636:            public static float fitText(Font font, String text, Rectangle rect,
0637:                    float maxFontSize, int runDirection) {
0638:                try {
0639:                    ColumnText ct = null;
0640:                    int status = 0;
0641:                    if (maxFontSize <= 0) {
0642:                        int cr = 0;
0643:                        int lf = 0;
0644:                        char t[] = text.toCharArray();
0645:                        for (int k = 0; k < t.length; ++k) {
0646:                            if (t[k] == '\n')
0647:                                ++lf;
0648:                            else if (t[k] == '\r')
0649:                                ++cr;
0650:                        }
0651:                        int minLines = Math.max(cr, lf) + 1;
0652:                        maxFontSize = Math.abs(rect.getHeight()) / minLines
0653:                                - 0.001f;
0654:                    }
0655:                    font.setSize(maxFontSize);
0656:                    Phrase ph = new Phrase(text, font);
0657:                    ct = new ColumnText(null);
0658:                    ct.setSimpleColumn(ph, rect.getLeft(), rect.getBottom(),
0659:                            rect.getRight(), rect.getTop(), maxFontSize,
0660:                            Element.ALIGN_LEFT);
0661:                    ct.setRunDirection(runDirection);
0662:                    status = ct.go(true);
0663:                    if ((status & ColumnText.NO_MORE_TEXT) != 0)
0664:                        return maxFontSize;
0665:                    float precision = 0.1f;
0666:                    float min = 0;
0667:                    float max = maxFontSize;
0668:                    float size = maxFontSize;
0669:                    for (int k = 0; k < 50; ++k) { //just in case it doesn't converge
0670:                        size = (min + max) / 2;
0671:                        ct = new ColumnText(null);
0672:                        font.setSize(size);
0673:                        ct.setSimpleColumn(new Phrase(text, font), rect
0674:                                .getLeft(), rect.getBottom(), rect.getRight(),
0675:                                rect.getTop(), size, Element.ALIGN_LEFT);
0676:                        ct.setRunDirection(runDirection);
0677:                        status = ct.go(true);
0678:                        if ((status & ColumnText.NO_MORE_TEXT) != 0) {
0679:                            if (max - min < size * precision)
0680:                                return size;
0681:                            min = size;
0682:                        } else
0683:                            max = size;
0684:                    }
0685:                    return size;
0686:                } catch (Exception e) {
0687:                    throw new ExceptionConverter(e);
0688:                }
0689:            }
0690:
0691:            /**
0692:             * Sets the digest/signature to an external calculated value.
0693:             * @param digest the digest. This is the actual signature
0694:             * @param RSAdata the extra data that goes into the data tag in PKCS#7
0695:             * @param digestEncryptionAlgorithm the encryption algorithm. It may must be <CODE>null</CODE> if the <CODE>digest</CODE>
0696:             * is also <CODE>null</CODE>. If the <CODE>digest</CODE> is not <CODE>null</CODE>
0697:             * then it may be "RSA" or "DSA"
0698:             */
0699:            public void setExternalDigest(byte digest[], byte RSAdata[],
0700:                    String digestEncryptionAlgorithm) {
0701:                externalDigest = digest;
0702:                externalRSAdata = RSAdata;
0703:                this .digestEncryptionAlgorithm = digestEncryptionAlgorithm;
0704:            }
0705:
0706:            /**
0707:             * Gets the signing reason.
0708:             * @return the signing reason
0709:             */
0710:            public String getReason() {
0711:                return this .reason;
0712:            }
0713:
0714:            /**
0715:             * Sets the signing reason.
0716:             * @param reason the signing reason
0717:             */
0718:            public void setReason(String reason) {
0719:                this .reason = reason;
0720:            }
0721:
0722:            /**
0723:             * Gets the signing location.
0724:             * @return the signing location
0725:             */
0726:            public String getLocation() {
0727:                return this .location;
0728:            }
0729:
0730:            /**
0731:             * Sets the signing location.
0732:             * @param location the signing location
0733:             */
0734:            public void setLocation(String location) {
0735:                this .location = location;
0736:            }
0737:
0738:            /**
0739:             * Returns the Cryptographic Service Provider that will sign the document.
0740:             * @return provider the name of the provider, for example "SUN",
0741:             * or <code>null</code> to use the default provider.
0742:             */
0743:            public String getProvider() {
0744:                return this .provider;
0745:            }
0746:
0747:            /**
0748:             * Sets the Cryptographic Service Provider that will sign the document.
0749:             *
0750:             * @param provider the name of the provider, for example "SUN", or
0751:             * <code>null</code> to use the default provider.
0752:             */
0753:            public void setProvider(String provider) {
0754:                this .provider = provider;
0755:            }
0756:
0757:            /**
0758:             * Gets the private key.
0759:             * @return the private key
0760:             */
0761:            public java.security.PrivateKey getPrivKey() {
0762:                return privKey;
0763:            }
0764:
0765:            /**
0766:             * Gets the certificate chain.
0767:             * @return the certificate chain
0768:             */
0769:            public java.security.cert.Certificate[] getCertChain() {
0770:                return this .certChain;
0771:            }
0772:
0773:            /**
0774:             * Gets the certificate revocation list.
0775:             * @return the certificate revocation list
0776:             */
0777:            public java.security.cert.CRL[] getCrlList() {
0778:                return this .crlList;
0779:            }
0780:
0781:            /**
0782:             * Gets the filter used to sign the document.
0783:             * @return the filter used to sign the document
0784:             */
0785:            public com.lowagie.text.pdf.PdfName getFilter() {
0786:                return filter;
0787:            }
0788:
0789:            /**
0790:             * Checks if a new field was created.
0791:             * @return <CODE>true</CODE> if a new field was created, <CODE>false</CODE> if signing
0792:             * an existing field or if the signature is invisible
0793:             */
0794:            public boolean isNewField() {
0795:                return this .newField;
0796:            }
0797:
0798:            /**
0799:             * Gets the page number of the field.
0800:             * @return the page number of the field
0801:             */
0802:            public int getPage() {
0803:                return page;
0804:            }
0805:
0806:            /**
0807:             * Gets the field name.
0808:             * @return the field name
0809:             */
0810:            public java.lang.String getFieldName() {
0811:                return fieldName;
0812:            }
0813:
0814:            /**
0815:             * Gets the rectangle that represent the position and dimension of the signature in the page.
0816:             * @return the rectangle that represent the position and dimension of the signature in the page
0817:             */
0818:            public com.lowagie.text.Rectangle getPageRect() {
0819:                return pageRect;
0820:            }
0821:
0822:            /**
0823:             * Gets the signature date.
0824:             * @return the signature date
0825:             */
0826:            public java.util.Calendar getSignDate() {
0827:                return signDate;
0828:            }
0829:
0830:            /**
0831:             * Sets the signature date.
0832:             * @param signDate the signature date
0833:             */
0834:            public void setSignDate(java.util.Calendar signDate) {
0835:                this .signDate = signDate;
0836:            }
0837:
0838:            com.lowagie.text.pdf.ByteBuffer getSigout() {
0839:                return sigout;
0840:            }
0841:
0842:            void setSigout(com.lowagie.text.pdf.ByteBuffer sigout) {
0843:                this .sigout = sigout;
0844:            }
0845:
0846:            java.io.OutputStream getOriginalout() {
0847:                return originalout;
0848:            }
0849:
0850:            void setOriginalout(java.io.OutputStream originalout) {
0851:                this .originalout = originalout;
0852:            }
0853:
0854:            /**
0855:             * Gets the temporary file.
0856:             * @return the temporary file or <CODE>null</CODE> is the document is created in memory
0857:             */
0858:            public java.io.File getTempFile() {
0859:                return tempFile;
0860:            }
0861:
0862:            void setTempFile(java.io.File tempFile) {
0863:                this .tempFile = tempFile;
0864:            }
0865:
0866:            /**
0867:             * Gets a new signature fied name that doesn't clash with any existing name.
0868:             * @return a new signature fied name
0869:             */
0870:            public String getNewSigName() {
0871:                AcroFields af = writer.getAcroFields();
0872:                String name = "Signature";
0873:                int step = 0;
0874:                boolean found = false;
0875:                while (!found) {
0876:                    ++step;
0877:                    String n1 = name + step;
0878:                    if (af.getFieldItem(n1) != null)
0879:                        continue;
0880:                    n1 += ".";
0881:                    found = true;
0882:                    for (Iterator it = af.getFields().keySet().iterator(); it
0883:                            .hasNext();) {
0884:                        String fn = (String) it.next();
0885:                        if (fn.startsWith(n1)) {
0886:                            found = false;
0887:                            break;
0888:                        }
0889:                    }
0890:                }
0891:                name += step;
0892:                return name;
0893:            }
0894:
0895:            /**
0896:             * This is the first method to be called when using external signatures. The general sequence is:
0897:             * preClose(), getDocumentBytes() and close().
0898:             * <p>
0899:             * If calling preClose() <B>dont't</B> call PdfStamper.close().
0900:             * <p>
0901:             * No external signatures are allowed if this methos is called.
0902:             * @throws IOException on error
0903:             * @throws DocumentException on error
0904:             */
0905:            public void preClose() throws IOException, DocumentException {
0906:                preClose(null);
0907:            }
0908:
0909:            /**
0910:             * This is the first method to be called when using external signatures. The general sequence is:
0911:             * preClose(), getDocumentBytes() and close().
0912:             * <p>
0913:             * If calling preClose() <B>dont't</B> call PdfStamper.close().
0914:             * <p>
0915:             * If using an external signature <CODE>exclusionSizes</CODE> must contain at least
0916:             * the <CODE>PdfName.CONTENTS</CODE> key with the size that it will take in the
0917:             * document. Note that due to the hex string coding this size should be
0918:             * byte_size*2+2.
0919:             * @param exclusionSizes a <CODE>HashMap</CODE> with names and sizes to be excluded in the signature
0920:             * calculation. The key is a <CODE>PdfName</CODE> and the value an
0921:             * <CODE>Integer</CODE>. At least the <CODE>PdfName.CONTENTS</CODE> must be present
0922:             * @throws IOException on error
0923:             * @throws DocumentException on error
0924:             */
0925:            public void preClose(HashMap exclusionSizes) throws IOException,
0926:                    DocumentException {
0927:                if (preClosed)
0928:                    throw new DocumentException("Document already pre closed.");
0929:                preClosed = true;
0930:                AcroFields af = writer.getAcroFields();
0931:                String name = getFieldName();
0932:                boolean fieldExists = !(isInvisible() || isNewField());
0933:                int flags = PdfAnnotation.FLAGS_PRINT
0934:                        | PdfAnnotation.FLAGS_LOCKED;
0935:                PdfIndirectReference refSig = writer.getPdfIndirectReference();
0936:                writer.setSigFlags(3);
0937:                if (fieldExists) {
0938:                    ArrayList widgets = af.getFieldItem(name).widgets;
0939:                    PdfDictionary widget = (PdfDictionary) widgets.get(0);
0940:                    writer.markUsed(widget);
0941:                    widget.put(PdfName.P, writer.getPageReference(getPage()));
0942:                    widget.put(PdfName.V, refSig);
0943:                    PdfObject obj = PdfReader.getPdfObjectRelease(widget
0944:                            .get(PdfName.F));
0945:                    if (obj != null && obj.isNumber())
0946:                        flags = ((PdfNumber) obj).intValue()
0947:                                | PdfAnnotation.FLAGS_LOCKED;
0948:                    widget.put(PdfName.F, new PdfNumber(flags));
0949:                    PdfDictionary ap = new PdfDictionary();
0950:                    ap.put(PdfName.N, getAppearance().getIndirectReference());
0951:                    widget.put(PdfName.AP, ap);
0952:                } else {
0953:                    PdfFormField sigField = PdfFormField
0954:                            .createSignature(writer);
0955:                    sigField.setFieldName(name);
0956:                    sigField.put(PdfName.V, refSig);
0957:                    sigField.setFlags(flags);
0958:
0959:                    int pagen = getPage();
0960:                    if (!isInvisible())
0961:                        sigField.setWidget(getPageRect(), null);
0962:                    else
0963:                        sigField.setWidget(new Rectangle(0, 0), null);
0964:                    sigField.setAppearance(PdfAnnotation.APPEARANCE_NORMAL,
0965:                            getAppearance());
0966:                    sigField.setPage(pagen);
0967:                    writer.addAnnotation(sigField, pagen);
0968:                }
0969:
0970:                exclusionLocations = new HashMap();
0971:                if (cryptoDictionary == null) {
0972:                    if (PdfName.ADOBE_PPKLITE.equals(getFilter()))
0973:                        sigStandard = new PdfSigGenericPKCS.PPKLite(
0974:                                getProvider());
0975:                    else if (PdfName.ADOBE_PPKMS.equals(getFilter()))
0976:                        sigStandard = new PdfSigGenericPKCS.PPKMS(getProvider());
0977:                    else if (PdfName.VERISIGN_PPKVS.equals(getFilter()))
0978:                        sigStandard = new PdfSigGenericPKCS.VeriSign(
0979:                                getProvider());
0980:                    else
0981:                        throw new IllegalArgumentException("Unknown filter: "
0982:                                + getFilter());
0983:                    sigStandard.setExternalDigest(externalDigest,
0984:                            externalRSAdata, digestEncryptionAlgorithm);
0985:                    if (getReason() != null)
0986:                        sigStandard.setReason(getReason());
0987:                    if (getLocation() != null)
0988:                        sigStandard.setLocation(getLocation());
0989:                    if (getContact() != null)
0990:                        sigStandard.setContact(getContact());
0991:                    sigStandard.put(PdfName.M, new PdfDate(getSignDate()));
0992:                    sigStandard.setSignInfo(getPrivKey(), getCertChain(),
0993:                            getCrlList());
0994:                    PdfString contents = (PdfString) sigStandard
0995:                            .get(PdfName.CONTENTS);
0996:                    PdfLiteral lit = new PdfLiteral((contents.toString()
0997:                            .length() + (PdfName.ADOBE_PPKLITE
0998:                            .equals(getFilter()) ? 0 : 64)) * 2 + 2);
0999:                    exclusionLocations.put(PdfName.CONTENTS, lit);
1000:                    sigStandard.put(PdfName.CONTENTS, lit);
1001:                    lit = new PdfLiteral(80);
1002:                    exclusionLocations.put(PdfName.BYTERANGE, lit);
1003:                    sigStandard.put(PdfName.BYTERANGE, lit);
1004:                    if (certificationLevel > 0) {
1005:                        addDocMDP(sigStandard);
1006:                    }
1007:                    if (signatureEvent != null)
1008:                        signatureEvent.getSignatureDictionary(sigStandard);
1009:                    writer.addToBody(sigStandard, refSig, false);
1010:                } else {
1011:                    PdfLiteral lit = new PdfLiteral(80);
1012:                    exclusionLocations.put(PdfName.BYTERANGE, lit);
1013:                    cryptoDictionary.put(PdfName.BYTERANGE, lit);
1014:                    for (Iterator it = exclusionSizes.entrySet().iterator(); it
1015:                            .hasNext();) {
1016:                        Map.Entry entry = (Map.Entry) it.next();
1017:                        PdfName key = (PdfName) entry.getKey();
1018:                        Integer v = (Integer) entry.getValue();
1019:                        lit = new PdfLiteral(v.intValue());
1020:                        exclusionLocations.put(key, lit);
1021:                        cryptoDictionary.put(key, lit);
1022:                    }
1023:                    if (certificationLevel > 0)
1024:                        addDocMDP(cryptoDictionary);
1025:                    if (signatureEvent != null)
1026:                        signatureEvent.getSignatureDictionary(cryptoDictionary);
1027:                    writer.addToBody(cryptoDictionary, refSig, false);
1028:                }
1029:                if (certificationLevel > 0) {
1030:                    // add DocMDP entry to root
1031:                    PdfDictionary docmdp = new PdfDictionary();
1032:                    docmdp.put(new PdfName("DocMDP"), refSig);
1033:                    writer.reader.getCatalog()
1034:                            .put(new PdfName("Perms"), docmdp);
1035:                }
1036:                writer.close(stamper.getMoreInfo());
1037:
1038:                range = new int[exclusionLocations.size() * 2];
1039:                int byteRangePosition = ((PdfLiteral) exclusionLocations
1040:                        .get(PdfName.BYTERANGE)).getPosition();
1041:                exclusionLocations.remove(PdfName.BYTERANGE);
1042:                int idx = 1;
1043:                for (Iterator it = exclusionLocations.values().iterator(); it
1044:                        .hasNext();) {
1045:                    PdfLiteral lit = (PdfLiteral) it.next();
1046:                    int n = lit.getPosition();
1047:                    range[idx++] = n;
1048:                    range[idx++] = lit.getPosLength() + n;
1049:                }
1050:                Arrays.sort(range, 1, range.length - 1);
1051:                for (int k = 3; k < range.length - 2; k += 2)
1052:                    range[k] -= range[k - 1];
1053:
1054:                if (tempFile == null) {
1055:                    bout = sigout.getBuffer();
1056:                    boutLen = sigout.size();
1057:                    range[range.length - 1] = boutLen - range[range.length - 2];
1058:                    ByteBuffer bf = new ByteBuffer();
1059:                    bf.append('[');
1060:                    for (int k = 0; k < range.length; ++k)
1061:                        bf.append(range[k]).append(' ');
1062:                    bf.append(']');
1063:                    System.arraycopy(bf.getBuffer(), 0, bout,
1064:                            byteRangePosition, bf.size());
1065:                } else {
1066:                    try {
1067:                        raf = new RandomAccessFile(tempFile, "rw");
1068:                        int boutLen = (int) raf.length();
1069:                        range[range.length - 1] = boutLen
1070:                                - range[range.length - 2];
1071:                        ByteBuffer bf = new ByteBuffer();
1072:                        bf.append('[');
1073:                        for (int k = 0; k < range.length; ++k)
1074:                            bf.append(range[k]).append(' ');
1075:                        bf.append(']');
1076:                        raf.seek(byteRangePosition);
1077:                        raf.write(bf.getBuffer(), 0, bf.size());
1078:                    } catch (IOException e) {
1079:                        try {
1080:                            raf.close();
1081:                        } catch (Exception ee) {
1082:                        }
1083:                        try {
1084:                            tempFile.delete();
1085:                        } catch (Exception ee) {
1086:                        }
1087:                        throw e;
1088:                    }
1089:                }
1090:            }
1091:
1092:            /**
1093:             * This is the last method to be called when using external signatures. The general sequence is:
1094:             * preClose(), getDocumentBytes() and close().
1095:             * <p>
1096:             * <CODE>update</CODE> is a <CODE>PdfDictionary</CODE> that must have exactly the
1097:             * same keys as the ones provided in {@link #preClose(HashMap)}.
1098:             * @param update a <CODE>PdfDictionary</CODE> with the key/value that will fill the holes defined
1099:             * in {@link #preClose(HashMap)}
1100:             * @throws DocumentException on error
1101:             * @throws IOException on error
1102:             */
1103:            public void close(PdfDictionary update) throws IOException,
1104:                    DocumentException {
1105:                try {
1106:                    if (!preClosed)
1107:                        throw new DocumentException(
1108:                                "preClose() must be called first.");
1109:                    ByteBuffer bf = new ByteBuffer();
1110:                    for (Iterator it = update.getKeys().iterator(); it
1111:                            .hasNext();) {
1112:                        PdfName key = (PdfName) it.next();
1113:                        PdfObject obj = update.get(key);
1114:                        PdfLiteral lit = (PdfLiteral) exclusionLocations
1115:                                .get(key);
1116:                        if (lit == null)
1117:                            throw new IllegalArgumentException("The key "
1118:                                    + key.toString()
1119:                                    + " didn't reserve space in preClose().");
1120:                        bf.reset();
1121:                        obj.toPdf(null, bf);
1122:                        if (bf.size() > lit.getPosLength())
1123:                            throw new IllegalArgumentException("The key "
1124:                                    + key.toString() + " is too big. Is "
1125:                                    + bf.size() + ", reserved "
1126:                                    + lit.getPosLength());
1127:                        if (tempFile == null)
1128:                            System.arraycopy(bf.getBuffer(), 0, bout, lit
1129:                                    .getPosition(), bf.size());
1130:                        else {
1131:                            raf.seek(lit.getPosition());
1132:                            raf.write(bf.getBuffer(), 0, bf.size());
1133:                        }
1134:                    }
1135:                    if (update.size() != exclusionLocations.size())
1136:                        throw new IllegalArgumentException(
1137:                                "The update dictionary has less keys than required.");
1138:                    if (tempFile == null) {
1139:                        originalout.write(bout, 0, boutLen);
1140:                    } else {
1141:                        if (originalout != null) {
1142:                            raf.seek(0);
1143:                            int length = (int) raf.length();
1144:                            byte buf[] = new byte[8192];
1145:                            while (length > 0) {
1146:                                int r = raf.read(buf, 0, Math.min(buf.length,
1147:                                        length));
1148:                                if (r < 0)
1149:                                    throw new EOFException("Unexpected EOF");
1150:                                originalout.write(buf, 0, r);
1151:                                length -= r;
1152:                            }
1153:                        }
1154:                    }
1155:                } finally {
1156:                    if (tempFile != null) {
1157:                        try {
1158:                            raf.close();
1159:                        } catch (Exception ee) {
1160:                        }
1161:                        if (originalout != null)
1162:                            try {
1163:                                tempFile.delete();
1164:                            } catch (Exception ee) {
1165:                            }
1166:                    }
1167:                    if (originalout != null)
1168:                        try {
1169:                            originalout.close();
1170:                        } catch (Exception e) {
1171:                        }
1172:                }
1173:            }
1174:
1175:            private void addDocMDP(PdfDictionary crypto) {
1176:                PdfDictionary reference = new PdfDictionary();
1177:                PdfDictionary transformParams = new PdfDictionary();
1178:                transformParams.put(PdfName.P,
1179:                        new PdfNumber(certificationLevel));
1180:                transformParams.put(PdfName.V, new PdfName("1.2"));
1181:                transformParams.put(PdfName.TYPE, PdfName.TRANSFORMPARAMS);
1182:                reference.put(PdfName.TRANSFORMMETHOD, PdfName.DOCMDP);
1183:                reference.put(PdfName.TYPE, PdfName.SIGREF);
1184:                reference.put(PdfName.TRANSFORMPARAMS, transformParams);
1185:                reference.put(new PdfName("DigestValue"), new PdfString("aa"));
1186:                PdfArray loc = new PdfArray();
1187:                loc.add(new PdfNumber(0));
1188:                loc.add(new PdfNumber(0));
1189:                reference.put(new PdfName("DigestLocation"), loc);
1190:                reference.put(new PdfName("DigestMethod"), new PdfName("MD5"));
1191:                reference.put(PdfName.DATA, writer.reader.getTrailer().get(
1192:                        PdfName.ROOT));
1193:                PdfArray types = new PdfArray();
1194:                types.add(reference);
1195:                crypto.put(PdfName.REFERENCE, types);
1196:            }
1197:
1198:            /**
1199:             * Gets the document bytes that are hashable when using external signatures. The general sequence is:
1200:             * preClose(), getRangeStream() and close().
1201:             * <p>
1202:             * @return the document bytes that are hashable
1203:             */
1204:            public InputStream getRangeStream() {
1205:                return new PdfSignatureAppearance.RangeStream(raf, bout, range);
1206:            }
1207:
1208:            /**
1209:             * Gets the user made signature dictionary. This is the dictionary at the /V key.
1210:             * @return the user made signature dictionary
1211:             */
1212:            public com.lowagie.text.pdf.PdfDictionary getCryptoDictionary() {
1213:                return cryptoDictionary;
1214:            }
1215:
1216:            /**
1217:             * Sets a user made signature dictionary. This is the dictionary at the /V key.
1218:             * @param cryptoDictionary a user made signature dictionary
1219:             */
1220:            public void setCryptoDictionary(
1221:                    com.lowagie.text.pdf.PdfDictionary cryptoDictionary) {
1222:                this .cryptoDictionary = cryptoDictionary;
1223:            }
1224:
1225:            /**
1226:             * Gets the <CODE>PdfStamper</CODE> associated with this instance.
1227:             * @return the <CODE>PdfStamper</CODE> associated with this instance
1228:             */
1229:            public com.lowagie.text.pdf.PdfStamper getStamper() {
1230:                return stamper;
1231:            }
1232:
1233:            void setStamper(com.lowagie.text.pdf.PdfStamper stamper) {
1234:                this .stamper = stamper;
1235:            }
1236:
1237:            /**
1238:             * Checks if the document is in the process of closing.
1239:             * @return <CODE>true</CODE> if the document is in the process of closing,
1240:             * <CODE>false</CODE> otherwise
1241:             */
1242:            public boolean isPreClosed() {
1243:                return preClosed;
1244:            }
1245:
1246:            /**
1247:             * Gets the instance of the standard signature dictionary. This instance
1248:             * is only available after pre close.
1249:             * <p>
1250:             * The main use is to insert external signatures.
1251:             * @return the instance of the standard signature dictionary
1252:             */
1253:            public com.lowagie.text.pdf.PdfSigGenericPKCS getSigStandard() {
1254:                return sigStandard;
1255:            }
1256:
1257:            /**
1258:             * Gets the signing contact.
1259:             * @return the signing contact
1260:             */
1261:            public String getContact() {
1262:                return this .contact;
1263:            }
1264:
1265:            /**
1266:             * Sets the signing contact.
1267:             * @param contact the signing contact
1268:             */
1269:            public void setContact(String contact) {
1270:                this .contact = contact;
1271:            }
1272:
1273:            /**
1274:             * Gets the n2 and n4 layer font.
1275:             * @return the n2 and n4 layer font
1276:             */
1277:            public Font getLayer2Font() {
1278:                return this .layer2Font;
1279:            }
1280:
1281:            /**
1282:             * Sets the n2 and n4 layer font. If the font size is zero, auto-fit will be used.
1283:             * @param layer2Font the n2 and n4 font
1284:             */
1285:            public void setLayer2Font(Font layer2Font) {
1286:                this .layer2Font = layer2Font;
1287:            }
1288:
1289:            /**
1290:             * Gets the Acrobat 6.0 layer mode.
1291:             * @return the Acrobat 6.0 layer mode
1292:             */
1293:            public boolean isAcro6Layers() {
1294:                return this .acro6Layers;
1295:            }
1296:
1297:            /**
1298:             * Acrobat 6.0 and higher recomends that only layer n2 and n4 be present. This method sets that mode.
1299:             * @param acro6Layers if <code>true</code> only the layers n2 and n4 will be present
1300:             */
1301:            public void setAcro6Layers(boolean acro6Layers) {
1302:                this .acro6Layers = acro6Layers;
1303:            }
1304:
1305:            /** Sets the run direction in the n2 and n4 layer. 
1306:             * @param runDirection the run direction
1307:             */
1308:            public void setRunDirection(int runDirection) {
1309:                if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT
1310:                        || runDirection > PdfWriter.RUN_DIRECTION_RTL)
1311:                    throw new RuntimeException("Invalid run direction: "
1312:                            + runDirection);
1313:                this .runDirection = runDirection;
1314:            }
1315:
1316:            /** Gets the run direction.
1317:             * @return the run direction
1318:             */
1319:            public int getRunDirection() {
1320:                return runDirection;
1321:            }
1322:
1323:            /**
1324:             * Getter for property signatureEvent.
1325:             * @return Value of property signatureEvent.
1326:             */
1327:            public SignatureEvent getSignatureEvent() {
1328:                return this .signatureEvent;
1329:            }
1330:
1331:            /**
1332:             * Sets the signature event to allow modification of the signature dictionary.
1333:             * @param signatureEvent the signature event
1334:             */
1335:            public void setSignatureEvent(SignatureEvent signatureEvent) {
1336:                this .signatureEvent = signatureEvent;
1337:            }
1338:
1339:            /**
1340:             * Gets the background image for the layer 2.
1341:             * @return the background image for the layer 2
1342:             */
1343:            public Image getImage() {
1344:                return this .image;
1345:            }
1346:
1347:            /**
1348:             * Sets the background image for the layer 2.
1349:             * @param image the background image for the layer 2
1350:             */
1351:            public void setImage(Image image) {
1352:                this .image = image;
1353:            }
1354:
1355:            /**
1356:             * Gets the scaling to be applied to the background image.
1357:             * @return the scaling to be applied to the background image
1358:             */
1359:            public float getImageScale() {
1360:                return this .imageScale;
1361:            }
1362:
1363:            /**
1364:             * Sets the scaling to be applied to the background image. If it's zero the image
1365:             * will fully fill the rectangle. If it's less than zero the image will fill the rectangle but
1366:             * will keep the proportions. If it's greater than zero that scaling will be applied.
1367:             * In any of the cases the image will always be centered. It's zero by default.
1368:             * @param imageScale the scaling to be applied to the background image
1369:             */
1370:            public void setImageScale(float imageScale) {
1371:                this .imageScale = imageScale;
1372:            }
1373:
1374:            /**
1375:             * Commands to draw a yellow question mark in a stream content
1376:             */
1377:            public static final String questionMark = "% DSUnknown\n" + "q\n"
1378:                    + "1 G\n" + "1 g\n" + "0.1 0 0 0.1 9 0 cm\n"
1379:                    + "0 J 0 j 4 M []0 d\n" + "1 i \n" + "0 g\n"
1380:                    + "313 292 m\n" + "313 404 325 453 432 529 c\n"
1381:                    + "478 561 504 597 504 645 c\n"
1382:                    + "504 736 440 760 391 760 c\n"
1383:                    + "286 760 271 681 265 626 c\n" + "265 625 l\n"
1384:                    + "100 625 l\n" + "100 828 253 898 381 898 c\n"
1385:                    + "451 898 679 878 679 650 c\n"
1386:                    + "679 555 628 499 538 435 c\n"
1387:                    + "488 399 467 376 467 292 c\n" + "313 292 l\n" + "h\n"
1388:                    + "308 214 170 -164 re\n" + "f\n" + "0.44 G\n" + "1.2 w\n"
1389:                    + "1 1 0.4 rg\n" + "287 318 m\n"
1390:                    + "287 430 299 479 406 555 c\n"
1391:                    + "451 587 478 623 478 671 c\n"
1392:                    + "478 762 414 786 365 786 c\n"
1393:                    + "260 786 245 707 239 652 c\n" + "239 651 l\n"
1394:                    + "74 651 l\n" + "74 854 227 924 355 924 c\n"
1395:                    + "425 924 653 904 653 676 c\n"
1396:                    + "653 581 602 525 512 461 c\n"
1397:                    + "462 425 441 402 441 318 c\n" + "287 318 l\n" + "h\n"
1398:                    + "282 240 170 -164 re\n" + "B\n" + "Q\n";
1399:
1400:            /**
1401:             * Holds value of property contact.
1402:             */
1403:            private String contact;
1404:
1405:            /**
1406:             * Holds value of property layer2Font.
1407:             */
1408:            private Font layer2Font;
1409:
1410:            /**
1411:             * Holds value of property layer4Text.
1412:             */
1413:            private String layer4Text;
1414:
1415:            /**
1416:             * Holds value of property acro6Layers.
1417:             */
1418:            private boolean acro6Layers;
1419:
1420:            /**
1421:             * Holds value of property runDirection.
1422:             */
1423:            private int runDirection = PdfWriter.RUN_DIRECTION_NO_BIDI;
1424:
1425:            /**
1426:             * Holds value of property signatureEvent.
1427:             */
1428:            private SignatureEvent signatureEvent;
1429:
1430:            /**
1431:             * Holds value of property image.
1432:             */
1433:            private Image image;
1434:
1435:            /**
1436:             * Holds value of property imageScale.
1437:             */
1438:            private float imageScale;
1439:
1440:            /**
1441:             *
1442:             */
1443:            private static class RangeStream extends InputStream {
1444:                private byte b[] = new byte[1];
1445:                private RandomAccessFile raf;
1446:                private byte bout[];
1447:                private int range[];
1448:                private int rangePosition = 0;
1449:
1450:                private RangeStream(RandomAccessFile raf, byte bout[],
1451:                        int range[]) {
1452:                    this .raf = raf;
1453:                    this .bout = bout;
1454:                    this .range = range;
1455:                }
1456:
1457:                /**
1458:                 * @see java.io.InputStream#read()
1459:                 */
1460:                public int read() throws IOException {
1461:                    int n = read(b);
1462:                    if (n != 1)
1463:                        return -1;
1464:                    return b[0] & 0xff;
1465:                }
1466:
1467:                /**
1468:                 * @see java.io.InputStream#read(byte[], int, int)
1469:                 */
1470:                public int read(byte[] b, int off, int len) throws IOException {
1471:                    if (b == null) {
1472:                        throw new NullPointerException();
1473:                    } else if ((off < 0) || (off > b.length) || (len < 0)
1474:                            || ((off + len) > b.length) || ((off + len) < 0)) {
1475:                        throw new IndexOutOfBoundsException();
1476:                    } else if (len == 0) {
1477:                        return 0;
1478:                    }
1479:                    if (rangePosition >= range[range.length - 2]
1480:                            + range[range.length - 1]) {
1481:                        return -1;
1482:                    }
1483:                    for (int k = 0; k < range.length; k += 2) {
1484:                        int start = range[k];
1485:                        int end = start + range[k + 1];
1486:                        if (rangePosition < start)
1487:                            rangePosition = start;
1488:                        if (rangePosition >= start && rangePosition < end) {
1489:                            int lenf = Math.min(len, end - rangePosition);
1490:                            if (raf == null)
1491:                                System.arraycopy(bout, rangePosition, b, off,
1492:                                        lenf);
1493:                            else {
1494:                                raf.seek(rangePosition);
1495:                                raf.readFully(b, off, lenf);
1496:                            }
1497:                            rangePosition += lenf;
1498:                            return lenf;
1499:                        }
1500:                    }
1501:                    return -1;
1502:                }
1503:            }
1504:
1505:            /**
1506:             * An interface to retrieve the signature dictionary for modification.
1507:             */
1508:            public interface SignatureEvent {
1509:                /**
1510:                 * Allows modification of the signature dictionary.
1511:                 * @param sig the signature dictionary
1512:                 */
1513:                public void getSignatureDictionary(PdfDictionary sig);
1514:            }
1515:
1516:            private int certificationLevel = NOT_CERTIFIED;
1517:
1518:            /**
1519:             * Gets the certified status of this document.
1520:             * @return the certified status
1521:             */
1522:            public int getCertificationLevel() {
1523:                return this .certificationLevel;
1524:            }
1525:
1526:            /**
1527:             * Sets the document type to certified instead of simply signed.
1528:             * @param certificationLevel the values can be: <code>NOT_CERTIFIED</code>, <code>CERTIFIED_NO_CHANGES_ALLOWED</code>,
1529:             * <code>CERTIFIED_FORM_FILLING</code> and <code>CERTIFIED_FORM_FILLING_AND_ANNOTATIONS</code>
1530:             */
1531:            public void setCertificationLevel(int certificationLevel) {
1532:                this.certificationLevel = certificationLevel;
1533:            }
1534:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.