Source Code Cross Referenced for AcroFields.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:         * Copyright 2003-2005 by Paulo Soares.
0003:         *
0004:         * The contents of this file are subject to the Mozilla Public License Version 1.1
0005:         * (the "License"); you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0007:         *
0008:         * Software distributed under the License is distributed on an "AS IS" basis,
0009:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0010:         * for the specific language governing rights and limitations under the License.
0011:         *
0012:         * The Original Code is 'iText, a free JAVA-PDF library'.
0013:         *
0014:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0015:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0016:         * All Rights Reserved.
0017:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0018:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0019:         *
0020:         * Contributor(s): all the names of the contributors are added in the source code
0021:         * where applicable.
0022:         *
0023:         * Alternatively, the contents of this file may be used under the terms of the
0024:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0025:         * provisions of LGPL are applicable instead of those above.  If you wish to
0026:         * allow use of your version of this file only under the terms of the LGPL
0027:         * License and not to allow others to use your version of this file under
0028:         * the MPL, indicate your decision by deleting the provisions above and
0029:         * replace them with the notice and other provisions required by the LGPL.
0030:         * If you do not delete the provisions above, a recipient may use your version
0031:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0032:         *
0033:         * This library is free software; you can redistribute it and/or modify it
0034:         * under the terms of the MPL as stated above or under the terms of the GNU
0035:         * Library General Public License as published by the Free Software Foundation;
0036:         * either version 2 of the License, or any later version.
0037:         *
0038:         * This library is distributed in the hope that it will be useful, but WITHOUT
0039:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0040:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0041:         * details.
0042:         *
0043:         * If you didn't download this code from the following link, you should check if
0044:         * you aren't using an obsolete version:
0045:         * http://www.lowagie.com/iText/
0046:         */
0047:        package com.lowagie.text.pdf;
0048:
0049:        import java.awt.Color;
0050:        import java.io.IOException;
0051:        import java.io.InputStream;
0052:        import java.util.ArrayList;
0053:        import java.util.Collections;
0054:        import java.util.Comparator;
0055:        import java.util.HashMap;
0056:        import java.util.Iterator;
0057:        import java.util.Map;
0058:
0059:        import org.w3c.dom.Node;
0060:
0061:        import com.lowagie.text.DocumentException;
0062:        import com.lowagie.text.Element;
0063:        import com.lowagie.text.ExceptionConverter;
0064:        import com.lowagie.text.Rectangle;
0065:
0066:        /** Query and change fields in existing documents either by method
0067:         * calls or by FDF merging.
0068:         * @author Paulo Soares (psoares@consiste.pt)
0069:         */
0070:        public class AcroFields {
0071:
0072:            PdfReader reader;
0073:            PdfWriter writer;
0074:            HashMap fields;
0075:            private int topFirst;
0076:            private HashMap sigNames;
0077:            private boolean append;
0078:            public static final int DA_FONT = 0;
0079:            public static final int DA_SIZE = 1;
0080:            public static final int DA_COLOR = 2;
0081:            private HashMap extensionFonts = new HashMap();
0082:            private XfaForm xfa;
0083:            /**
0084:             * A field type invalid or not found.
0085:             */
0086:            public static final int FIELD_TYPE_NONE = 0;
0087:            /**
0088:             * A field type.
0089:             */
0090:            public static final int FIELD_TYPE_PUSHBUTTON = 1;
0091:            /**
0092:             * A field type.
0093:             */
0094:            public static final int FIELD_TYPE_CHECKBOX = 2;
0095:            /**
0096:             * A field type.
0097:             */
0098:            public static final int FIELD_TYPE_RADIOBUTTON = 3;
0099:            /**
0100:             * A field type.
0101:             */
0102:            public static final int FIELD_TYPE_TEXT = 4;
0103:            /**
0104:             * A field type.
0105:             */
0106:            public static final int FIELD_TYPE_LIST = 5;
0107:            /**
0108:             * A field type.
0109:             */
0110:            public static final int FIELD_TYPE_COMBO = 6;
0111:            /**
0112:             * A field type.
0113:             */
0114:            public static final int FIELD_TYPE_SIGNATURE = 7;
0115:
0116:            private boolean lastWasString;
0117:
0118:            /** Holds value of property generateAppearances. */
0119:            private boolean generateAppearances = true;
0120:
0121:            private HashMap localFonts = new HashMap();
0122:
0123:            private float extraMarginLeft;
0124:            private float extraMarginTop;
0125:            private ArrayList substitutionFonts;
0126:
0127:            AcroFields(PdfReader reader, PdfWriter writer) {
0128:                this .reader = reader;
0129:                this .writer = writer;
0130:                try {
0131:                    xfa = new XfaForm(reader);
0132:                } catch (Exception e) {
0133:                    throw new ExceptionConverter(e);
0134:                }
0135:                if (writer instanceof  PdfStamperImp) {
0136:                    append = ((PdfStamperImp) writer).isAppend();
0137:                }
0138:                fill();
0139:            }
0140:
0141:            void fill() {
0142:                fields = new HashMap();
0143:                PdfDictionary top = (PdfDictionary) PdfReader
0144:                        .getPdfObjectRelease(reader.getCatalog().get(
0145:                                PdfName.ACROFORM));
0146:                if (top == null)
0147:                    return;
0148:                PdfArray arrfds = (PdfArray) PdfReader.getPdfObjectRelease(top
0149:                        .get(PdfName.FIELDS));
0150:                if (arrfds == null || arrfds.size() == 0)
0151:                    return;
0152:                arrfds = null;
0153:                for (int k = 1; k <= reader.getNumberOfPages(); ++k) {
0154:                    PdfDictionary page = reader.getPageNRelease(k);
0155:                    PdfArray annots = (PdfArray) PdfReader.getPdfObjectRelease(
0156:                            page.get(PdfName.ANNOTS), page);
0157:                    if (annots == null)
0158:                        continue;
0159:                    ArrayList arr = annots.getArrayList();
0160:                    for (int j = 0; j < arr.size(); ++j) {
0161:                        PdfObject annoto = PdfReader.getPdfObject(
0162:                                (PdfObject) arr.get(j), annots);
0163:                        if (!(annoto instanceof  PdfDictionary)) {
0164:                            PdfReader.releaseLastXrefPartial((PdfObject) arr
0165:                                    .get(j));
0166:                            continue;
0167:                        }
0168:                        PdfDictionary annot = (PdfDictionary) annoto;
0169:                        if (!PdfName.WIDGET.equals(annot.get(PdfName.SUBTYPE))) {
0170:                            PdfReader.releaseLastXrefPartial((PdfObject) arr
0171:                                    .get(j));
0172:                            continue;
0173:                        }
0174:                        PdfDictionary widget = annot;
0175:                        PdfDictionary dic = new PdfDictionary();
0176:                        dic.putAll(annot);
0177:                        String name = "";
0178:                        PdfDictionary value = null;
0179:                        PdfObject lastV = null;
0180:                        while (annot != null) {
0181:                            dic.mergeDifferent(annot);
0182:                            PdfString t = (PdfString) PdfReader
0183:                                    .getPdfObject(annot.get(PdfName.T));
0184:                            if (t != null)
0185:                                name = t.toUnicodeString() + "." + name;
0186:                            if (lastV == null && annot.get(PdfName.V) != null)
0187:                                lastV = PdfReader.getPdfObjectRelease(annot
0188:                                        .get(PdfName.V));
0189:                            if (value == null && t != null) {
0190:                                value = annot;
0191:                                if (annot.get(PdfName.V) == null
0192:                                        && lastV != null)
0193:                                    value.put(PdfName.V, lastV);
0194:                            }
0195:                            annot = (PdfDictionary) PdfReader.getPdfObject(
0196:                                    annot.get(PdfName.PARENT), annot);
0197:                        }
0198:                        if (name.length() > 0)
0199:                            name = name.substring(0, name.length() - 1);
0200:                        Item item = (Item) fields.get(name);
0201:                        if (item == null) {
0202:                            item = new Item();
0203:                            fields.put(name, item);
0204:                        }
0205:                        if (value == null)
0206:                            item.values.add(widget);
0207:                        else
0208:                            item.values.add(value);
0209:                        item.widgets.add(widget);
0210:                        item.widget_refs.add(arr.get(j)); // must be a reference
0211:                        if (top != null)
0212:                            dic.mergeDifferent(top);
0213:                        item.merged.add(dic);
0214:                        item.page.add(new Integer(k));
0215:                        item.tabOrder.add(new Integer(j));
0216:                    }
0217:                }
0218:            }
0219:
0220:            /** Gets the list of appearance names. Use it to get the names allowed
0221:             * with radio and checkbox fields. If the /Opt key exists the values will
0222:             * also be included. The name 'Off' may also be valid
0223:             * even if not returned in the list.
0224:             * @param fieldName the fully qualified field name
0225:             * @return the list of names or <CODE>null</CODE> if the field does not exist
0226:             */
0227:            public String[] getAppearanceStates(String fieldName) {
0228:                Item fd = (Item) fields.get(fieldName);
0229:                if (fd == null)
0230:                    return null;
0231:                HashMap names = new HashMap();
0232:                PdfDictionary vals = (PdfDictionary) fd.values.get(0);
0233:                PdfObject opts = PdfReader.getPdfObject(vals.get(PdfName.OPT));
0234:                if (opts != null) {
0235:                    if (opts.isString())
0236:                        names.put(((PdfString) opts).toUnicodeString(), null);
0237:                    else if (opts.isArray()) {
0238:                        ArrayList list = ((PdfArray) opts).getArrayList();
0239:                        for (int k = 0; k < list.size(); ++k) {
0240:                            PdfObject v = PdfReader
0241:                                    .getPdfObject((PdfObject) list.get(k));
0242:                            if (v != null && v.isString())
0243:                                names.put(((PdfString) v).toUnicodeString(),
0244:                                        null);
0245:                        }
0246:                    }
0247:                }
0248:                ArrayList wd = fd.widgets;
0249:                for (int k = 0; k < wd.size(); ++k) {
0250:                    PdfDictionary dic = (PdfDictionary) wd.get(k);
0251:                    dic = (PdfDictionary) PdfReader.getPdfObject(dic
0252:                            .get(PdfName.AP));
0253:                    if (dic == null)
0254:                        continue;
0255:                    PdfObject ob = PdfReader.getPdfObject(dic.get(PdfName.N));
0256:                    if (ob == null || !ob.isDictionary())
0257:                        continue;
0258:                    dic = (PdfDictionary) ob;
0259:                    for (Iterator it = dic.getKeys().iterator(); it.hasNext();) {
0260:                        String name = PdfName.decodeName(((PdfName) it.next())
0261:                                .toString());
0262:                        names.put(name, null);
0263:                    }
0264:                }
0265:                String out[] = new String[names.size()];
0266:                return (String[]) names.keySet().toArray(out);
0267:            }
0268:
0269:            private String[] getListOption(String fieldName, int idx) {
0270:                Item fd = getFieldItem(fieldName);
0271:                if (fd == null)
0272:                    return null;
0273:                PdfObject obj = PdfReader
0274:                        .getPdfObject(((PdfDictionary) fd.merged.get(0))
0275:                                .get(PdfName.OPT));
0276:                if (obj == null || !obj.isArray())
0277:                    return null;
0278:                PdfArray ar = (PdfArray) obj;
0279:                String[] ret = new String[ar.size()];
0280:                ArrayList a = ar.getArrayList();
0281:                for (int k = 0; k < a.size(); ++k) {
0282:                    obj = PdfReader.getPdfObject((PdfObject) a.get(k));
0283:                    try {
0284:                        if (obj.isArray()) {
0285:                            obj = (PdfObject) ((PdfArray) obj).getArrayList()
0286:                                    .get(idx);
0287:                        }
0288:                        if (obj.isString())
0289:                            ret[k] = ((PdfString) obj).toUnicodeString();
0290:                        else
0291:                            ret[k] = obj.toString();
0292:                    } catch (Exception e) {
0293:                        ret[k] = "";
0294:                    }
0295:                }
0296:                return ret;
0297:            }
0298:
0299:            /**
0300:             * Gets the list of export option values from fields of type list or combo.
0301:             * If the field doesn't exist or the field type is not list or combo it will return
0302:             * <CODE>null</CODE>.
0303:             * @param fieldName the field name
0304:             * @return the list of export option values from fields of type list or combo
0305:             */
0306:            public String[] getListOptionExport(String fieldName) {
0307:                return getListOption(fieldName, 0);
0308:            }
0309:
0310:            /**
0311:             * Gets the list of display option values from fields of type list or combo.
0312:             * If the field doesn't exist or the field type is not list or combo it will return
0313:             * <CODE>null</CODE>.
0314:             * @param fieldName the field name
0315:             * @return the list of export option values from fields of type list or combo
0316:             */
0317:            public String[] getListOptionDisplay(String fieldName) {
0318:                return getListOption(fieldName, 1);
0319:            }
0320:
0321:            /**
0322:             * Sets the option list for fields of type list or combo. One of <CODE>exportValues</CODE>
0323:             * or <CODE>displayValues</CODE> may be <CODE>null</CODE> but not both. This method will only
0324:             * set the list but will not set the value or appearance. For that, calling <CODE>setField()</CODE>
0325:             * is required.
0326:             * <p>
0327:             * An example:
0328:             * <p>
0329:             * <PRE>
0330:             * PdfReader pdf = new PdfReader("input.pdf");
0331:             * PdfStamper stp = new PdfStamper(pdf, new FileOutputStream("output.pdf"));
0332:             * AcroFields af = stp.getAcroFields();
0333:             * af.setListOption("ComboBox", new String[]{"a", "b", "c"}, new String[]{"first", "second", "third"});
0334:             * af.setField("ComboBox", "b");
0335:             * stp.close();
0336:             * </PRE>
0337:             * @param fieldName the field name
0338:             * @param exportValues the export values
0339:             * @param displayValues the display values
0340:             * @return <CODE>true</CODE> if the operation succeeded, <CODE>false</CODE> otherwise
0341:             */
0342:            public boolean setListOption(String fieldName,
0343:                    String[] exportValues, String[] displayValues) {
0344:                if (exportValues == null && displayValues == null)
0345:                    return false;
0346:                if (exportValues != null && displayValues != null
0347:                        && exportValues.length != displayValues.length)
0348:                    throw new IllegalArgumentException(
0349:                            "The export and the display array must have the same size.");
0350:                int ftype = getFieldType(fieldName);
0351:                if (ftype != FIELD_TYPE_COMBO && ftype != FIELD_TYPE_LIST)
0352:                    return false;
0353:                Item fd = (Item) fields.get(fieldName);
0354:                String[] sing = null;
0355:                if (exportValues == null && displayValues != null)
0356:                    sing = displayValues;
0357:                else if (exportValues != null && displayValues == null)
0358:                    sing = exportValues;
0359:                PdfArray opt = new PdfArray();
0360:                if (sing != null) {
0361:                    for (int k = 0; k < sing.length; ++k)
0362:                        opt.add(new PdfString(sing[k], PdfObject.TEXT_UNICODE));
0363:                } else {
0364:                    for (int k = 0; k < exportValues.length; ++k) {
0365:                        PdfArray a = new PdfArray();
0366:                        a.add(new PdfString(exportValues[k],
0367:                                PdfObject.TEXT_UNICODE));
0368:                        a.add(new PdfString(displayValues[k],
0369:                                PdfObject.TEXT_UNICODE));
0370:                        opt.add(a);
0371:                    }
0372:                }
0373:                ((PdfDictionary) fd.values.get(0)).put(PdfName.OPT, opt);
0374:                for (int j = 0; j < fd.merged.size(); ++j)
0375:                    ((PdfDictionary) fd.merged.get(j)).put(PdfName.OPT, opt);
0376:                return true;
0377:            }
0378:
0379:            /**
0380:             * Gets the field type. The type can be one of: <CODE>FIELD_TYPE_PUSHBUTTON</CODE>,
0381:             * <CODE>FIELD_TYPE_CHECKBOX</CODE>, <CODE>FIELD_TYPE_RADIOBUTTON</CODE>,
0382:             * <CODE>FIELD_TYPE_TEXT</CODE>, <CODE>FIELD_TYPE_LIST</CODE>,
0383:             * <CODE>FIELD_TYPE_COMBO</CODE> or <CODE>FIELD_TYPE_SIGNATURE</CODE>.
0384:             * <p>
0385:             * If the field does not exist or is invalid it returns
0386:             * <CODE>FIELD_TYPE_NONE</CODE>.
0387:             * @param fieldName the field name
0388:             * @return the field type
0389:             */
0390:            public int getFieldType(String fieldName) {
0391:                Item fd = getFieldItem(fieldName);
0392:                if (fd == null)
0393:                    return FIELD_TYPE_NONE;
0394:                PdfObject type = PdfReader
0395:                        .getPdfObject(((PdfDictionary) fd.merged.get(0))
0396:                                .get(PdfName.FT));
0397:                if (type == null)
0398:                    return FIELD_TYPE_NONE;
0399:                int ff = 0;
0400:                PdfObject ffo = PdfReader
0401:                        .getPdfObject(((PdfDictionary) fd.merged.get(0))
0402:                                .get(PdfName.FF));
0403:                if (ffo != null && ffo.type() == PdfObject.NUMBER)
0404:                    ff = ((PdfNumber) ffo).intValue();
0405:                if (PdfName.BTN.equals(type)) {
0406:                    if ((ff & PdfFormField.FF_PUSHBUTTON) != 0)
0407:                        return FIELD_TYPE_PUSHBUTTON;
0408:                    if ((ff & PdfFormField.FF_RADIO) != 0)
0409:                        return FIELD_TYPE_RADIOBUTTON;
0410:                    else
0411:                        return FIELD_TYPE_CHECKBOX;
0412:                } else if (PdfName.TX.equals(type)) {
0413:                    return FIELD_TYPE_TEXT;
0414:                } else if (PdfName.CH.equals(type)) {
0415:                    if ((ff & PdfFormField.FF_COMBO) != 0)
0416:                        return FIELD_TYPE_COMBO;
0417:                    else
0418:                        return FIELD_TYPE_LIST;
0419:                } else if (PdfName.SIG.equals(type)) {
0420:                    return FIELD_TYPE_SIGNATURE;
0421:                }
0422:                return FIELD_TYPE_NONE;
0423:            }
0424:
0425:            /**
0426:             * Export the fields as a FDF.
0427:             * @param writer the FDF writer
0428:             */
0429:            public void exportAsFdf(FdfWriter writer) {
0430:                for (Iterator it = fields.entrySet().iterator(); it.hasNext();) {
0431:                    Map.Entry entry = (Map.Entry) it.next();
0432:                    Item item = (Item) entry.getValue();
0433:                    String name = (String) entry.getKey();
0434:                    PdfObject v = PdfReader
0435:                            .getPdfObject(((PdfDictionary) item.merged.get(0))
0436:                                    .get(PdfName.V));
0437:                    if (v == null)
0438:                        continue;
0439:                    String value = getField(name);
0440:                    if (lastWasString)
0441:                        writer.setFieldAsString(name, value);
0442:                    else
0443:                        writer.setFieldAsName(name, value);
0444:                }
0445:            }
0446:
0447:            /**
0448:             * Renames a field. Only the last part of the name can be renamed. For example,
0449:             * if the original field is "ab.cd.ef" only the "ef" part can be renamed.
0450:             * @param oldName the old field name
0451:             * @param newName the new field name
0452:             * @return <CODE>true</CODE> if the renaming was successful, <CODE>false</CODE>
0453:             * otherwise
0454:             */
0455:            public boolean renameField(String oldName, String newName) {
0456:                int idx1 = oldName.lastIndexOf('.') + 1;
0457:                int idx2 = newName.lastIndexOf('.') + 1;
0458:                if (idx1 != idx2)
0459:                    return false;
0460:                if (!oldName.substring(0, idx1).equals(
0461:                        newName.substring(0, idx2)))
0462:                    return false;
0463:                if (fields.containsKey(newName))
0464:                    return false;
0465:                Item item = (Item) fields.get(oldName);
0466:                if (item == null)
0467:                    return false;
0468:                newName = newName.substring(idx2);
0469:                PdfString ss = new PdfString(newName, PdfObject.TEXT_UNICODE);
0470:                for (int k = 0; k < item.merged.size(); ++k) {
0471:                    PdfDictionary dic = (PdfDictionary) item.values.get(k);
0472:                    dic.put(PdfName.T, ss);
0473:                    markUsed(dic);
0474:                    dic = (PdfDictionary) item.merged.get(k);
0475:                    dic.put(PdfName.T, ss);
0476:                }
0477:                fields.remove(oldName);
0478:                fields.put(newName, item);
0479:                return true;
0480:            }
0481:
0482:            public static Object[] splitDAelements(String da) {
0483:                try {
0484:                    PRTokeniser tk = new PRTokeniser(PdfEncodings
0485:                            .convertToBytes(da, null));
0486:                    ArrayList stack = new ArrayList();
0487:                    Object ret[] = new Object[3];
0488:                    while (tk.nextToken()) {
0489:                        if (tk.getTokenType() == PRTokeniser.TK_COMMENT)
0490:                            continue;
0491:                        if (tk.getTokenType() == PRTokeniser.TK_OTHER) {
0492:                            String operator = tk.getStringValue();
0493:                            if (operator.equals("Tf")) {
0494:                                if (stack.size() >= 2) {
0495:                                    ret[DA_FONT] = stack.get(stack.size() - 2);
0496:                                    ret[DA_SIZE] = new Float((String) stack
0497:                                            .get(stack.size() - 1));
0498:                                }
0499:                            } else if (operator.equals("g")) {
0500:                                if (stack.size() >= 1) {
0501:                                    float gray = new Float((String) stack
0502:                                            .get(stack.size() - 1))
0503:                                            .floatValue();
0504:                                    if (gray != 0)
0505:                                        ret[DA_COLOR] = new GrayColor(gray);
0506:                                }
0507:                            } else if (operator.equals("rg")) {
0508:                                if (stack.size() >= 3) {
0509:                                    float red = new Float((String) stack
0510:                                            .get(stack.size() - 3))
0511:                                            .floatValue();
0512:                                    float green = new Float((String) stack
0513:                                            .get(stack.size() - 2))
0514:                                            .floatValue();
0515:                                    float blue = new Float((String) stack
0516:                                            .get(stack.size() - 1))
0517:                                            .floatValue();
0518:                                    ret[DA_COLOR] = new Color(red, green, blue);
0519:                                }
0520:                            } else if (operator.equals("k")) {
0521:                                if (stack.size() >= 4) {
0522:                                    float cyan = new Float((String) stack
0523:                                            .get(stack.size() - 4))
0524:                                            .floatValue();
0525:                                    float magenta = new Float((String) stack
0526:                                            .get(stack.size() - 3))
0527:                                            .floatValue();
0528:                                    float yellow = new Float((String) stack
0529:                                            .get(stack.size() - 2))
0530:                                            .floatValue();
0531:                                    float black = new Float((String) stack
0532:                                            .get(stack.size() - 1))
0533:                                            .floatValue();
0534:                                    ret[DA_COLOR] = new CMYKColor(cyan,
0535:                                            magenta, yellow, black);
0536:                                }
0537:                            }
0538:                            stack.clear();
0539:                        } else
0540:                            stack.add(tk.getStringValue());
0541:                    }
0542:                    return ret;
0543:                } catch (IOException ioe) {
0544:                    throw new ExceptionConverter(ioe);
0545:                }
0546:            }
0547:
0548:            public void decodeGenericDictionary(PdfDictionary merged,
0549:                    BaseField tx) throws IOException, DocumentException {
0550:                int flags = 0;
0551:                // the text size and color
0552:                PdfString da = (PdfString) PdfReader.getPdfObject(merged
0553:                        .get(PdfName.DA));
0554:                if (da != null) {
0555:                    Object dab[] = splitDAelements(da.toUnicodeString());
0556:                    if (dab[DA_SIZE] != null)
0557:                        tx.setFontSize(((Float) dab[DA_SIZE]).floatValue());
0558:                    if (dab[DA_COLOR] != null)
0559:                        tx.setTextColor((Color) dab[DA_COLOR]);
0560:                    if (dab[DA_FONT] != null) {
0561:                        PdfDictionary font = (PdfDictionary) PdfReader
0562:                                .getPdfObject(merged.get(PdfName.DR));
0563:                        if (font != null) {
0564:                            font = (PdfDictionary) PdfReader.getPdfObject(font
0565:                                    .get(PdfName.FONT));
0566:                            if (font != null) {
0567:                                PdfObject po = font.get(new PdfName(
0568:                                        (String) dab[DA_FONT]));
0569:                                if (po != null
0570:                                        && po.type() == PdfObject.INDIRECT) {
0571:                                    PRIndirectReference por = (PRIndirectReference) po;
0572:                                    BaseFont bp = new DocumentFont(
0573:                                            (PRIndirectReference) po);
0574:                                    tx.setFont(bp);
0575:                                    Integer porkey = new Integer(por
0576:                                            .getNumber());
0577:                                    BaseFont porf = (BaseFont) extensionFonts
0578:                                            .get(porkey);
0579:                                    if (porf == null) {
0580:                                        if (!extensionFonts.containsKey(porkey)) {
0581:                                            PdfDictionary fo = (PdfDictionary) PdfReader
0582:                                                    .getPdfObject(po);
0583:                                            PdfDictionary fd = (PdfDictionary) PdfReader
0584:                                                    .getPdfObject(fo
0585:                                                            .get(PdfName.FONTDESCRIPTOR));
0586:                                            if (fd != null) {
0587:                                                PRStream prs = (PRStream) PdfReader
0588:                                                        .getPdfObject(fd
0589:                                                                .get(PdfName.FONTFILE2));
0590:                                                if (prs == null)
0591:                                                    prs = (PRStream) PdfReader
0592:                                                            .getPdfObject(fd
0593:                                                                    .get(PdfName.FONTFILE3));
0594:                                                if (prs == null) {
0595:                                                    extensionFonts.put(porkey,
0596:                                                            null);
0597:                                                } else {
0598:                                                    try {
0599:                                                        porf = BaseFont
0600:                                                                .createFont(
0601:                                                                        "font.ttf",
0602:                                                                        BaseFont.IDENTITY_H,
0603:                                                                        true,
0604:                                                                        false,
0605:                                                                        PdfReader
0606:                                                                                .getStreamBytes(prs),
0607:                                                                        null);
0608:                                                    } catch (Exception e) {
0609:                                                    }
0610:                                                    extensionFonts.put(porkey,
0611:                                                            porf);
0612:                                                }
0613:                                            }
0614:                                        }
0615:                                    }
0616:                                    if (tx instanceof  TextField)
0617:                                        ((TextField) tx).setExtensionFont(porf);
0618:                                } else {
0619:                                    BaseFont bf = (BaseFont) localFonts
0620:                                            .get(dab[DA_FONT]);
0621:                                    if (bf == null) {
0622:                                        String fn[] = (String[]) stdFieldFontNames
0623:                                                .get(dab[DA_FONT]);
0624:                                        if (fn != null) {
0625:                                            try {
0626:                                                String enc = "winansi";
0627:                                                if (fn.length > 1)
0628:                                                    enc = fn[1];
0629:                                                bf = BaseFont.createFont(fn[0],
0630:                                                        enc, false);
0631:                                                tx.setFont(bf);
0632:                                            } catch (Exception e) {
0633:                                                // empty
0634:                                            }
0635:                                        }
0636:                                    } else
0637:                                        tx.setFont(bf);
0638:                                }
0639:                            }
0640:                        }
0641:                    }
0642:                }
0643:                //rotation, border and backgound color
0644:                PdfDictionary mk = (PdfDictionary) PdfReader
0645:                        .getPdfObject(merged.get(PdfName.MK));
0646:                if (mk != null) {
0647:                    PdfArray ar = (PdfArray) PdfReader.getPdfObject(mk
0648:                            .get(PdfName.BC));
0649:                    Color border = getMKColor(ar);
0650:                    tx.setBorderColor(border);
0651:                    if (border != null)
0652:                        tx.setBorderWidth(1);
0653:                    ar = (PdfArray) PdfReader.getPdfObject(mk.get(PdfName.BG));
0654:                    tx.setBackgroundColor(getMKColor(ar));
0655:                    PdfNumber rotation = (PdfNumber) PdfReader.getPdfObject(mk
0656:                            .get(PdfName.R));
0657:                    if (rotation != null)
0658:                        tx.setRotation(rotation.intValue());
0659:                }
0660:                //flags
0661:                PdfNumber nfl = (PdfNumber) PdfReader.getPdfObject(merged
0662:                        .get(PdfName.F));
0663:                flags = 0;
0664:                if (nfl != null) {
0665:                    flags = nfl.intValue();
0666:                    if ((flags & PdfFormField.FLAGS_PRINT) != 0
0667:                            && (flags & PdfFormField.FLAGS_HIDDEN) != 0)
0668:                        tx.setVisibility(BaseField.HIDDEN);
0669:                    else if ((flags & PdfFormField.FLAGS_PRINT) != 0
0670:                            && (flags & PdfFormField.FLAGS_NOVIEW) != 0)
0671:                        tx.setVisibility(BaseField.HIDDEN_BUT_PRINTABLE);
0672:                    else if ((flags & PdfFormField.FLAGS_PRINT) != 0)
0673:                        tx.setVisibility(BaseField.VISIBLE);
0674:                    else
0675:                        tx.setVisibility(BaseField.VISIBLE_BUT_DOES_NOT_PRINT);
0676:                }
0677:                //multiline
0678:                nfl = (PdfNumber) PdfReader
0679:                        .getPdfObject(merged.get(PdfName.FF));
0680:                flags = 0;
0681:                if (nfl != null)
0682:                    flags = nfl.intValue();
0683:                tx.setOptions(flags);
0684:                if ((flags & PdfFormField.FF_COMB) != 0) {
0685:                    PdfNumber maxLen = (PdfNumber) PdfReader
0686:                            .getPdfObject(merged.get(PdfName.MAXLEN));
0687:                    int len = 0;
0688:                    if (maxLen != null)
0689:                        len = maxLen.intValue();
0690:                    tx.setMaxCharacterLength(len);
0691:                }
0692:                //alignment
0693:                nfl = (PdfNumber) PdfReader.getPdfObject(merged.get(PdfName.Q));
0694:                if (nfl != null) {
0695:                    if (nfl.intValue() == PdfFormField.Q_CENTER)
0696:                        tx.setAlignment(Element.ALIGN_CENTER);
0697:                    else if (nfl.intValue() == PdfFormField.Q_RIGHT)
0698:                        tx.setAlignment(Element.ALIGN_RIGHT);
0699:                }
0700:                //border styles
0701:                PdfDictionary bs = (PdfDictionary) PdfReader
0702:                        .getPdfObject(merged.get(PdfName.BS));
0703:                if (bs != null) {
0704:                    PdfNumber w = (PdfNumber) PdfReader.getPdfObject(bs
0705:                            .get(PdfName.W));
0706:                    if (w != null)
0707:                        tx.setBorderWidth(w.floatValue());
0708:                    PdfName s = (PdfName) PdfReader.getPdfObject(bs
0709:                            .get(PdfName.S));
0710:                    if (PdfName.D.equals(s))
0711:                        tx.setBorderStyle(PdfBorderDictionary.STYLE_DASHED);
0712:                    else if (PdfName.B.equals(s))
0713:                        tx.setBorderStyle(PdfBorderDictionary.STYLE_BEVELED);
0714:                    else if (PdfName.I.equals(s))
0715:                        tx.setBorderStyle(PdfBorderDictionary.STYLE_INSET);
0716:                    else if (PdfName.U.equals(s))
0717:                        tx.setBorderStyle(PdfBorderDictionary.STYLE_UNDERLINE);
0718:                } else {
0719:                    PdfArray bd = (PdfArray) PdfReader.getPdfObject(merged
0720:                            .get(PdfName.BORDER));
0721:                    if (bd != null) {
0722:                        ArrayList ar = bd.getArrayList();
0723:                        if (ar.size() >= 3)
0724:                            tx.setBorderWidth(((PdfNumber) ar.get(2))
0725:                                    .floatValue());
0726:                        if (ar.size() >= 4)
0727:                            tx.setBorderStyle(PdfBorderDictionary.STYLE_DASHED);
0728:                    }
0729:                }
0730:            }
0731:
0732:            PdfAppearance getAppearance(PdfDictionary merged, String text,
0733:                    String fieldName) throws IOException, DocumentException {
0734:                topFirst = 0;
0735:                TextField tx = null;
0736:                if (fieldCache == null || !fieldCache.containsKey(fieldName)) {
0737:                    tx = new TextField(writer, null, null);
0738:                    tx.setExtraMargin(extraMarginLeft, extraMarginTop);
0739:                    tx.setBorderWidth(0);
0740:                    tx.setSubstitutionFonts(substitutionFonts);
0741:                    decodeGenericDictionary(merged, tx);
0742:                    //rect
0743:                    PdfArray rect = (PdfArray) PdfReader.getPdfObject(merged
0744:                            .get(PdfName.RECT));
0745:                    Rectangle box = PdfReader.getNormalizedRectangle(rect);
0746:                    if (tx.getRotation() == 90 || tx.getRotation() == 270)
0747:                        box = box.rotate();
0748:                    tx.setBox(box);
0749:                    if (fieldCache != null)
0750:                        fieldCache.put(fieldName, tx);
0751:                } else {
0752:                    tx = (TextField) fieldCache.get(fieldName);
0753:                    tx.setWriter(writer);
0754:                }
0755:                PdfName fieldType = (PdfName) PdfReader.getPdfObject(merged
0756:                        .get(PdfName.FT));
0757:                if (PdfName.TX.equals(fieldType)) {
0758:                    tx.setText(text);
0759:                    return tx.getAppearance();
0760:                }
0761:                if (!PdfName.CH.equals(fieldType))
0762:                    throw new DocumentException(
0763:                            "An appearance was requested without a variable text field.");
0764:                PdfArray opt = (PdfArray) PdfReader.getPdfObject(merged
0765:                        .get(PdfName.OPT));
0766:                int flags = 0;
0767:                PdfNumber nfl = (PdfNumber) PdfReader.getPdfObject(merged
0768:                        .get(PdfName.FF));
0769:                if (nfl != null)
0770:                    flags = nfl.intValue();
0771:                if ((flags & PdfFormField.FF_COMBO) != 0 && opt == null) {
0772:                    tx.setText(text);
0773:                    return tx.getAppearance();
0774:                }
0775:                if (opt != null) {
0776:                    ArrayList op = opt.getArrayList();
0777:                    String choices[] = new String[op.size()];
0778:                    String choicesExp[] = new String[op.size()];
0779:                    for (int k = 0; k < op.size(); ++k) {
0780:                        PdfObject obj = (PdfObject) op.get(k);
0781:                        if (obj.isString()) {
0782:                            choices[k] = choicesExp[k] = ((PdfString) obj)
0783:                                    .toUnicodeString();
0784:                        } else {
0785:                            ArrayList opar = ((PdfArray) obj).getArrayList();
0786:                            choicesExp[k] = ((PdfString) opar.get(0))
0787:                                    .toUnicodeString();
0788:                            choices[k] = ((PdfString) opar.get(1))
0789:                                    .toUnicodeString();
0790:                        }
0791:                    }
0792:                    if ((flags & PdfFormField.FF_COMBO) != 0) {
0793:                        for (int k = 0; k < choices.length; ++k) {
0794:                            if (text.equals(choicesExp[k])) {
0795:                                text = choices[k];
0796:                                break;
0797:                            }
0798:                        }
0799:                        tx.setText(text);
0800:                        return tx.getAppearance();
0801:                    }
0802:                    int idx = 0;
0803:                    for (int k = 0; k < choicesExp.length; ++k) {
0804:                        if (text.equals(choicesExp[k])) {
0805:                            idx = k;
0806:                            break;
0807:                        }
0808:                    }
0809:                    tx.setChoices(choices);
0810:                    tx.setChoiceExports(choicesExp);
0811:                    tx.setChoiceSelection(idx);
0812:                }
0813:                PdfAppearance app = tx.getListAppearance();
0814:                topFirst = tx.getTopFirst();
0815:                return app;
0816:            }
0817:
0818:            Color getMKColor(PdfArray ar) {
0819:                if (ar == null)
0820:                    return null;
0821:                ArrayList cc = ar.getArrayList();
0822:                switch (cc.size()) {
0823:                case 1:
0824:                    return new GrayColor(((PdfNumber) cc.get(0)).floatValue());
0825:                case 3:
0826:                    return new Color(ExtendedColor.normalize(((PdfNumber) cc
0827:                            .get(0)).floatValue()), ExtendedColor
0828:                            .normalize(((PdfNumber) cc.get(1)).floatValue()),
0829:                            ExtendedColor.normalize(((PdfNumber) cc.get(2))
0830:                                    .floatValue()));
0831:                case 4:
0832:                    return new CMYKColor(((PdfNumber) cc.get(0)).floatValue(),
0833:                            ((PdfNumber) cc.get(1)).floatValue(),
0834:                            ((PdfNumber) cc.get(2)).floatValue(),
0835:                            ((PdfNumber) cc.get(3)).floatValue());
0836:                default:
0837:                    return null;
0838:                }
0839:            }
0840:
0841:            /** Gets the field value.
0842:             * @param name the fully qualified field name
0843:             * @return the field value
0844:             */
0845:            public String getField(String name) {
0846:                if (xfa.isXfaPresent()) {
0847:                    name = xfa.findFieldName(name, this );
0848:                    if (name == null)
0849:                        return null;
0850:                    name = XfaForm.Xml2Som.getShortName(name);
0851:                    return XfaForm.getNodeText(xfa.findDatasetsNode(name));
0852:                }
0853:                Item item = (Item) fields.get(name);
0854:                if (item == null)
0855:                    return null;
0856:                lastWasString = false;
0857:                PdfObject v = PdfReader
0858:                        .getPdfObject(((PdfDictionary) item.merged.get(0))
0859:                                .get(PdfName.V));
0860:                if (v == null)
0861:                    return "";
0862:                PdfName type = (PdfName) PdfReader
0863:                        .getPdfObject(((PdfDictionary) item.merged.get(0))
0864:                                .get(PdfName.FT));
0865:                if (PdfName.BTN.equals(type)) {
0866:                    PdfNumber ff = (PdfNumber) PdfReader
0867:                            .getPdfObject(((PdfDictionary) item.merged.get(0))
0868:                                    .get(PdfName.FF));
0869:                    int flags = 0;
0870:                    if (ff != null)
0871:                        flags = ff.intValue();
0872:                    if ((flags & PdfFormField.FF_PUSHBUTTON) != 0)
0873:                        return "";
0874:                    String value = "";
0875:                    if (v.isName())
0876:                        value = PdfName.decodeName(v.toString());
0877:                    else if (v.isString())
0878:                        value = ((PdfString) v).toUnicodeString();
0879:                    PdfObject opts = PdfReader
0880:                            .getPdfObject(((PdfDictionary) item.values.get(0))
0881:                                    .get(PdfName.OPT));
0882:                    if (opts != null && opts.isArray()) {
0883:                        ArrayList list = ((PdfArray) opts).getArrayList();
0884:                        int idx = 0;
0885:                        try {
0886:                            idx = Integer.parseInt(value);
0887:                            PdfString ps = (PdfString) list.get(idx);
0888:                            value = ps.toUnicodeString();
0889:                            lastWasString = true;
0890:                        } catch (Exception e) {
0891:                        }
0892:                    }
0893:                    return value;
0894:                }
0895:                if (v.isString()) {
0896:                    lastWasString = true;
0897:                    return ((PdfString) v).toUnicodeString();
0898:                }
0899:                return PdfName.decodeName(v.toString());
0900:            }
0901:
0902:            /**
0903:             * Sets a field property. Valid property names are:
0904:             * <p>
0905:             * <ul>
0906:             * <li>textfont - sets the text font. The value for this entry is a <CODE>BaseFont</CODE>.<br>
0907:             * <li>textcolor - sets the text color. The value for this entry is a <CODE>java.awt.Color</CODE>.<br>
0908:             * <li>textsize - sets the text size. The value for this entry is a <CODE>Float</CODE>.
0909:             * <li>bgcolor - sets the background color. The value for this entry is a <CODE>java.awt.Color</CODE>.
0910:             *     If <code>null</code> removes the background.<br>
0911:             * <li>bordercolor - sets the border color. The value for this entry is a <CODE>java.awt.Color</CODE>.
0912:             *     If <code>null</code> removes the border.<br>
0913:             * </ul>
0914:             * @param field the field name
0915:             * @param name the property name
0916:             * @param value the property value
0917:             * @param inst an array of <CODE>int</CODE> indexing into <CODE>AcroField.Item.merged</CODE> elements to process.
0918:             * Set to <CODE>null</CODE> to process all
0919:             * @return <CODE>true</CODE> if the property exists, <CODE>false</CODE> otherwise
0920:             */
0921:            public boolean setFieldProperty(String field, String name,
0922:                    Object value, int inst[]) {
0923:                if (writer == null)
0924:                    throw new RuntimeException(
0925:                            "This AcroFields instance is read-only.");
0926:                try {
0927:                    Item item = (Item) fields.get(field);
0928:                    if (item == null)
0929:                        return false;
0930:                    InstHit hit = new InstHit(inst);
0931:                    if (name.equalsIgnoreCase("textfont")) {
0932:                        for (int k = 0; k < item.merged.size(); ++k) {
0933:                            if (hit.isHit(k)) {
0934:                                PdfString da = (PdfString) PdfReader
0935:                                        .getPdfObject(((PdfDictionary) item.merged
0936:                                                .get(k)).get(PdfName.DA));
0937:                                PdfDictionary dr = (PdfDictionary) PdfReader
0938:                                        .getPdfObject(((PdfDictionary) item.merged
0939:                                                .get(k)).get(PdfName.DR));
0940:                                if (da != null && dr != null) {
0941:                                    Object dao[] = splitDAelements(da
0942:                                            .toUnicodeString());
0943:                                    PdfAppearance cb = new PdfAppearance();
0944:                                    if (dao[DA_FONT] != null) {
0945:                                        BaseFont bf = (BaseFont) value;
0946:                                        PdfName psn = (PdfName) PdfAppearance.stdFieldFontNames
0947:                                                .get(bf.getPostscriptFontName());
0948:                                        if (psn == null) {
0949:                                            psn = new PdfName(bf
0950:                                                    .getPostscriptFontName());
0951:                                        }
0952:                                        PdfDictionary fonts = (PdfDictionary) PdfReader
0953:                                                .getPdfObject(dr
0954:                                                        .get(PdfName.FONT));
0955:                                        if (fonts == null) {
0956:                                            fonts = new PdfDictionary();
0957:                                            dr.put(PdfName.FONT, fonts);
0958:                                        }
0959:                                        PdfIndirectReference fref = (PdfIndirectReference) fonts
0960:                                                .get(psn);
0961:                                        PdfDictionary top = (PdfDictionary) PdfReader
0962:                                                .getPdfObject(reader
0963:                                                        .getCatalog()
0964:                                                        .get(PdfName.ACROFORM));
0965:                                        markUsed(top);
0966:                                        dr = (PdfDictionary) PdfReader
0967:                                                .getPdfObject(top
0968:                                                        .get(PdfName.DR));
0969:                                        if (dr == null) {
0970:                                            dr = new PdfDictionary();
0971:                                            top.put(PdfName.DR, dr);
0972:                                        }
0973:                                        markUsed(dr);
0974:                                        PdfDictionary fontsTop = (PdfDictionary) PdfReader
0975:                                                .getPdfObject(dr
0976:                                                        .get(PdfName.FONT));
0977:                                        if (fontsTop == null) {
0978:                                            fontsTop = new PdfDictionary();
0979:                                            dr.put(PdfName.FONT, fontsTop);
0980:                                        }
0981:                                        markUsed(fontsTop);
0982:                                        PdfIndirectReference frefTop = (PdfIndirectReference) fontsTop
0983:                                                .get(psn);
0984:                                        if (frefTop != null) {
0985:                                            if (fref == null)
0986:                                                fonts.put(psn, frefTop);
0987:                                        } else if (fref == null) {
0988:                                            FontDetails fd;
0989:                                            if (bf.getFontType() == BaseFont.FONT_TYPE_DOCUMENT) {
0990:                                                fd = new FontDetails(
0991:                                                        null,
0992:                                                        ((DocumentFont) bf)
0993:                                                                .getIndirectReference(),
0994:                                                        bf);
0995:                                            } else {
0996:                                                bf.setSubset(false);
0997:                                                fd = writer.addSimple(bf);
0998:                                                localFonts.put(psn.toString()
0999:                                                        .substring(1), bf);
1000:                                            }
1001:                                            fontsTop.put(psn, fd
1002:                                                    .getIndirectReference());
1003:                                            fonts.put(psn, fd
1004:                                                    .getIndirectReference());
1005:                                        }
1006:                                        ByteBuffer buf = cb.getInternalBuffer();
1007:                                        buf.append(psn.getBytes()).append(' ')
1008:                                                .append(
1009:                                                        ((Float) dao[DA_SIZE])
1010:                                                                .floatValue())
1011:                                                .append(" Tf ");
1012:                                        if (dao[DA_COLOR] != null)
1013:                                            cb
1014:                                                    .setColorFill((Color) dao[DA_COLOR]);
1015:                                        PdfString s = new PdfString(cb
1016:                                                .toString());
1017:                                        ((PdfDictionary) item.merged.get(k))
1018:                                                .put(PdfName.DA, s);
1019:                                        ((PdfDictionary) item.widgets.get(k))
1020:                                                .put(PdfName.DA, s);
1021:                                        markUsed((PdfDictionary) item.widgets
1022:                                                .get(k));
1023:                                    }
1024:                                }
1025:                            }
1026:                        }
1027:                    } else if (name.equalsIgnoreCase("textcolor")) {
1028:                        for (int k = 0; k < item.merged.size(); ++k) {
1029:                            if (hit.isHit(k)) {
1030:                                PdfString da = (PdfString) PdfReader
1031:                                        .getPdfObject(((PdfDictionary) item.merged
1032:                                                .get(k)).get(PdfName.DA));
1033:                                if (da != null) {
1034:                                    Object dao[] = splitDAelements(da
1035:                                            .toUnicodeString());
1036:                                    PdfAppearance cb = new PdfAppearance();
1037:                                    if (dao[DA_FONT] != null) {
1038:                                        ByteBuffer buf = cb.getInternalBuffer();
1039:                                        buf.append(
1040:                                                new PdfName(
1041:                                                        (String) dao[DA_FONT])
1042:                                                        .getBytes())
1043:                                                .append(' ').append(
1044:                                                        ((Float) dao[DA_SIZE])
1045:                                                                .floatValue())
1046:                                                .append(" Tf ");
1047:                                        cb.setColorFill((Color) value);
1048:                                        PdfString s = new PdfString(cb
1049:                                                .toString());
1050:                                        ((PdfDictionary) item.merged.get(k))
1051:                                                .put(PdfName.DA, s);
1052:                                        ((PdfDictionary) item.widgets.get(k))
1053:                                                .put(PdfName.DA, s);
1054:                                        markUsed((PdfDictionary) item.widgets
1055:                                                .get(k));
1056:                                    }
1057:                                }
1058:                            }
1059:                        }
1060:                    } else if (name.equalsIgnoreCase("textsize")) {
1061:                        for (int k = 0; k < item.merged.size(); ++k) {
1062:                            if (hit.isHit(k)) {
1063:                                PdfString da = (PdfString) PdfReader
1064:                                        .getPdfObject(((PdfDictionary) item.merged
1065:                                                .get(k)).get(PdfName.DA));
1066:                                if (da != null) {
1067:                                    Object dao[] = splitDAelements(da
1068:                                            .toUnicodeString());
1069:                                    PdfAppearance cb = new PdfAppearance();
1070:                                    if (dao[DA_FONT] != null) {
1071:                                        ByteBuffer buf = cb.getInternalBuffer();
1072:                                        buf.append(
1073:                                                new PdfName(
1074:                                                        (String) dao[DA_FONT])
1075:                                                        .getBytes())
1076:                                                .append(' ').append(
1077:                                                        ((Float) value)
1078:                                                                .floatValue())
1079:                                                .append(" Tf ");
1080:                                        if (dao[DA_COLOR] != null)
1081:                                            cb
1082:                                                    .setColorFill((Color) dao[DA_COLOR]);
1083:                                        PdfString s = new PdfString(cb
1084:                                                .toString());
1085:                                        ((PdfDictionary) item.merged.get(k))
1086:                                                .put(PdfName.DA, s);
1087:                                        ((PdfDictionary) item.widgets.get(k))
1088:                                                .put(PdfName.DA, s);
1089:                                        markUsed((PdfDictionary) item.widgets
1090:                                                .get(k));
1091:                                    }
1092:                                }
1093:                            }
1094:                        }
1095:                    } else if (name.equalsIgnoreCase("bgcolor")
1096:                            || name.equalsIgnoreCase("bordercolor")) {
1097:                        PdfName dname = (name.equalsIgnoreCase("bgcolor") ? PdfName.BG
1098:                                : PdfName.BC);
1099:                        for (int k = 0; k < item.merged.size(); ++k) {
1100:                            if (hit.isHit(k)) {
1101:                                PdfObject obj = PdfReader
1102:                                        .getPdfObject(((PdfDictionary) item.merged
1103:                                                .get(k)).get(PdfName.MK));
1104:                                markUsed(obj);
1105:                                PdfDictionary mk = (PdfDictionary) obj;
1106:                                if (mk == null) {
1107:                                    if (value == null)
1108:                                        return true;
1109:                                    mk = new PdfDictionary();
1110:                                    ((PdfDictionary) item.merged.get(k)).put(
1111:                                            PdfName.MK, mk);
1112:                                    ((PdfDictionary) item.widgets.get(k)).put(
1113:                                            PdfName.MK, mk);
1114:                                    markUsed((PdfDictionary) item.widgets
1115:                                            .get(k));
1116:                                }
1117:                                if (value == null)
1118:                                    mk.remove(dname);
1119:                                else
1120:                                    mk.put(dname, PdfFormField
1121:                                            .getMKColor((Color) value));
1122:                            }
1123:                        }
1124:                    } else
1125:                        return false;
1126:                    return true;
1127:                } catch (Exception e) {
1128:                    throw new ExceptionConverter(e);
1129:                }
1130:            }
1131:
1132:            /**
1133:             * Sets a field property. Valid property names are:
1134:             * <p>
1135:             * <ul>
1136:             * <li>flags - a set of flags specifying various characteristics of the field's widget annotation.
1137:             * The value of this entry replaces that of the F entry in the form's corresponding annotation dictionary.<br>
1138:             * <li>setflags - a set of flags to be set (turned on) in the F entry of the form's corresponding
1139:             * widget annotation dictionary. Bits equal to 1 cause the corresponding bits in F to be set to 1.<br>
1140:             * <li>clrflags - a set of flags to be cleared (turned off) in the F entry of the form's corresponding
1141:             * widget annotation dictionary. Bits equal to 1 cause the corresponding
1142:             * bits in F to be set to 0.<br>
1143:             * <li>fflags - a set of flags specifying various characteristics of the field. The value
1144:             * of this entry replaces that of the Ff entry in the form's corresponding field dictionary.<br>
1145:             * <li>setfflags - a set of flags to be set (turned on) in the Ff entry of the form's corresponding
1146:             * field dictionary. Bits equal to 1 cause the corresponding bits in Ff to be set to 1.<br>
1147:             * <li>clrfflags - a set of flags to be cleared (turned off) in the Ff entry of the form's corresponding
1148:             * field dictionary. Bits equal to 1 cause the corresponding bits in Ff
1149:             * to be set to 0.<br>
1150:             * </ul>
1151:             * @param field the field name
1152:             * @param name the property name
1153:             * @param value the property value
1154:             * @param inst an array of <CODE>int</CODE> indexing into <CODE>AcroField.Item.merged</CODE> elements to process.
1155:             * Set to <CODE>null</CODE> to process all
1156:             * @return <CODE>true</CODE> if the property exists, <CODE>false</CODE> otherwise
1157:             */
1158:            public boolean setFieldProperty(String field, String name,
1159:                    int value, int inst[]) {
1160:                if (writer == null)
1161:                    throw new RuntimeException(
1162:                            "This AcroFields instance is read-only.");
1163:                Item item = (Item) fields.get(field);
1164:                if (item == null)
1165:                    return false;
1166:                InstHit hit = new InstHit(inst);
1167:                if (name.equalsIgnoreCase("flags")) {
1168:                    PdfNumber num = new PdfNumber(value);
1169:                    for (int k = 0; k < item.merged.size(); ++k) {
1170:                        if (hit.isHit(k)) {
1171:                            ((PdfDictionary) item.merged.get(k)).put(PdfName.F,
1172:                                    num);
1173:                            ((PdfDictionary) item.widgets.get(k)).put(
1174:                                    PdfName.F, num);
1175:                            markUsed((PdfDictionary) item.widgets.get(k));
1176:                        }
1177:                    }
1178:                } else if (name.equalsIgnoreCase("setflags")) {
1179:                    for (int k = 0; k < item.merged.size(); ++k) {
1180:                        if (hit.isHit(k)) {
1181:                            PdfNumber num = (PdfNumber) PdfReader
1182:                                    .getPdfObject(((PdfDictionary) item.widgets
1183:                                            .get(k)).get(PdfName.F));
1184:                            int val = 0;
1185:                            if (num != null)
1186:                                val = num.intValue();
1187:                            num = new PdfNumber(val | value);
1188:                            ((PdfDictionary) item.merged.get(k)).put(PdfName.F,
1189:                                    num);
1190:                            ((PdfDictionary) item.widgets.get(k)).put(
1191:                                    PdfName.F, num);
1192:                            markUsed((PdfDictionary) item.widgets.get(k));
1193:                        }
1194:                    }
1195:                } else if (name.equalsIgnoreCase("clrflags")) {
1196:                    for (int k = 0; k < item.merged.size(); ++k) {
1197:                        if (hit.isHit(k)) {
1198:                            PdfNumber num = (PdfNumber) PdfReader
1199:                                    .getPdfObject(((PdfDictionary) item.widgets
1200:                                            .get(k)).get(PdfName.F));
1201:                            int val = 0;
1202:                            if (num != null)
1203:                                val = num.intValue();
1204:                            num = new PdfNumber(val & (~value));
1205:                            ((PdfDictionary) item.merged.get(k)).put(PdfName.F,
1206:                                    num);
1207:                            ((PdfDictionary) item.widgets.get(k)).put(
1208:                                    PdfName.F, num);
1209:                            markUsed((PdfDictionary) item.widgets.get(k));
1210:                        }
1211:                    }
1212:                } else if (name.equalsIgnoreCase("fflags")) {
1213:                    PdfNumber num = new PdfNumber(value);
1214:                    for (int k = 0; k < item.merged.size(); ++k) {
1215:                        if (hit.isHit(k)) {
1216:                            ((PdfDictionary) item.merged.get(k)).put(
1217:                                    PdfName.FF, num);
1218:                            ((PdfDictionary) item.values.get(k)).put(
1219:                                    PdfName.FF, num);
1220:                            markUsed((PdfDictionary) item.values.get(k));
1221:                        }
1222:                    }
1223:                } else if (name.equalsIgnoreCase("setfflags")) {
1224:                    for (int k = 0; k < item.merged.size(); ++k) {
1225:                        if (hit.isHit(k)) {
1226:                            PdfNumber num = (PdfNumber) PdfReader
1227:                                    .getPdfObject(((PdfDictionary) item.values
1228:                                            .get(k)).get(PdfName.FF));
1229:                            int val = 0;
1230:                            if (num != null)
1231:                                val = num.intValue();
1232:                            num = new PdfNumber(val | value);
1233:                            ((PdfDictionary) item.merged.get(k)).put(
1234:                                    PdfName.FF, num);
1235:                            ((PdfDictionary) item.values.get(k)).put(
1236:                                    PdfName.FF, num);
1237:                            markUsed((PdfDictionary) item.values.get(k));
1238:                        }
1239:                    }
1240:                } else if (name.equalsIgnoreCase("clrfflags")) {
1241:                    for (int k = 0; k < item.merged.size(); ++k) {
1242:                        if (hit.isHit(k)) {
1243:                            PdfNumber num = (PdfNumber) PdfReader
1244:                                    .getPdfObject(((PdfDictionary) item.values
1245:                                            .get(k)).get(PdfName.FF));
1246:                            int val = 0;
1247:                            if (num != null)
1248:                                val = num.intValue();
1249:                            num = new PdfNumber(val & (~value));
1250:                            ((PdfDictionary) item.merged.get(k)).put(
1251:                                    PdfName.FF, num);
1252:                            ((PdfDictionary) item.values.get(k)).put(
1253:                                    PdfName.FF, num);
1254:                            markUsed((PdfDictionary) item.values.get(k));
1255:                        }
1256:                    }
1257:                } else
1258:                    return false;
1259:                return true;
1260:            }
1261:
1262:            /**
1263:             * Merges an XML data structure into this form.
1264:             * @param n the top node of the data structure
1265:             * @throws java.io.IOException on error
1266:             * @throws com.lowagie.text.DocumentException o error
1267:             */
1268:            public void mergeXfaData(Node n) throws IOException,
1269:                    DocumentException {
1270:                XfaForm.Xml2SomDatasets data = new XfaForm.Xml2SomDatasets(n);
1271:                for (Iterator it = data.getOrder().iterator(); it.hasNext();) {
1272:                    String name = (String) it.next();
1273:                    String text = XfaForm.getNodeText((Node) data
1274:                            .getName2Node().get(name));
1275:                    setField(name, text);
1276:                }
1277:            }
1278:
1279:            /** Sets the fields by FDF merging.
1280:             * @param fdf the FDF form
1281:             * @throws IOException on error
1282:             * @throws DocumentException on error
1283:             */
1284:            public void setFields(FdfReader fdf) throws IOException,
1285:                    DocumentException {
1286:                HashMap fd = fdf.getFields();
1287:                for (Iterator i = fd.keySet().iterator(); i.hasNext();) {
1288:                    String f = (String) i.next();
1289:                    String v = fdf.getFieldValue(f);
1290:                    if (v != null)
1291:                        setField(f, v);
1292:                }
1293:            }
1294:
1295:            /** Sets the fields by XFDF merging.
1296:             * @param xfdf the XFDF form
1297:             * @throws IOException on error
1298:             * @throws DocumentException on error
1299:             */
1300:
1301:            public void setFields(XfdfReader xfdf) throws IOException,
1302:                    DocumentException {
1303:                HashMap fd = xfdf.getFields();
1304:                for (Iterator i = fd.keySet().iterator(); i.hasNext();) {
1305:                    String f = (String) i.next();
1306:                    String v = xfdf.getFieldValue(f);
1307:                    if (v != null)
1308:                        setField(f, v);
1309:                }
1310:            }
1311:
1312:            /**
1313:             * Regenerates the field appearance.
1314:             * This is usefull when you change a field property, but not its value,
1315:             * for instance form.setFieldProperty("f", "bgcolor", Color.BLUE, null);
1316:             * This won't have any effect, unless you use regenerateField("f") after changing
1317:             * the property.
1318:             * 
1319:             * @param name the fully qualified field name or the partial name in the case of XFA forms
1320:             * @throws IOException on error
1321:             * @throws DocumentException on error
1322:             * @return <CODE>true</CODE> if the field was found and changed,
1323:             * <CODE>false</CODE> otherwise
1324:             */
1325:            public boolean regenerateField(String name) throws IOException,
1326:                    DocumentException {
1327:                String value = getField(name);
1328:                return setField(name, value, value);
1329:            }
1330:
1331:            /** Sets the field value.
1332:             * @param name the fully qualified field name or the partial name in the case of XFA forms
1333:             * @param value the field value
1334:             * @throws IOException on error
1335:             * @throws DocumentException on error
1336:             * @return <CODE>true</CODE> if the field was found and changed,
1337:             * <CODE>false</CODE> otherwise
1338:             */
1339:            public boolean setField(String name, String value)
1340:                    throws IOException, DocumentException {
1341:                return setField(name, value, null);
1342:            }
1343:
1344:            /** Sets the field value and the display string. The display string
1345:             * is used to build the appearance in the cases where the value
1346:             * is modified by Acrobat with JavaScript and the algorithm is
1347:             * known.
1348:             * @param name the fully qualified field name or the partial name in the case of XFA forms
1349:             * @param value the field value
1350:             * @param display the string that is used for the appearance. If <CODE>null</CODE>
1351:             * the <CODE>value</CODE> parameter will be used
1352:             * @return <CODE>true</CODE> if the field was found and changed,
1353:             * <CODE>false</CODE> otherwise
1354:             * @throws IOException on error
1355:             * @throws DocumentException on error
1356:             */
1357:            public boolean setField(String name, String value, String display)
1358:                    throws IOException, DocumentException {
1359:                if (writer == null)
1360:                    throw new DocumentException(
1361:                            "This AcroFields instance is read-only.");
1362:                if (xfa.isXfaPresent()) {
1363:                    name = xfa.findFieldName(name, this );
1364:                    if (name == null)
1365:                        return false;
1366:                    String shortName = XfaForm.Xml2Som.getShortName(name);
1367:                    Node xn = xfa.findDatasetsNode(shortName);
1368:                    if (xn == null) {
1369:                        xn = xfa.getDatasetsSom().insertNode(
1370:                                xfa.getDatasetsNode(), shortName);
1371:                    }
1372:                    xfa.setNodeText(xn, value);
1373:                }
1374:                Item item = (Item) fields.get(name);
1375:                if (item == null)
1376:                    return false;
1377:                PdfName type = (PdfName) PdfReader
1378:                        .getPdfObject(((PdfDictionary) item.merged.get(0))
1379:                                .get(PdfName.FT));
1380:                if (PdfName.TX.equals(type)) {
1381:                    PdfNumber maxLen = (PdfNumber) PdfReader
1382:                            .getPdfObject(((PdfDictionary) item.merged.get(0))
1383:                                    .get(PdfName.MAXLEN));
1384:                    int len = 0;
1385:                    if (maxLen != null)
1386:                        len = maxLen.intValue();
1387:                    if (len > 0)
1388:                        value = value.substring(0, Math
1389:                                .min(len, value.length()));
1390:                }
1391:                if (display == null)
1392:                    display = value;
1393:                if (PdfName.TX.equals(type) || PdfName.CH.equals(type)) {
1394:                    PdfString v = new PdfString(value, PdfObject.TEXT_UNICODE);
1395:                    for (int idx = 0; idx < item.values.size(); ++idx) {
1396:                        PdfDictionary valueDic = (PdfDictionary) item.values
1397:                                .get(idx);
1398:                        valueDic.put(PdfName.V, v);
1399:                        valueDic.remove(PdfName.I);
1400:                        markUsed(valueDic);
1401:                        PdfDictionary merged = (PdfDictionary) item.merged
1402:                                .get(idx);
1403:                        merged.remove(PdfName.I);
1404:                        merged.put(PdfName.V, v);
1405:                        PdfDictionary widget = (PdfDictionary) item.widgets
1406:                                .get(idx);
1407:                        if (generateAppearances) {
1408:                            PdfAppearance app = getAppearance(merged, display,
1409:                                    name);
1410:                            if (PdfName.CH.equals(type)) {
1411:                                PdfNumber n = new PdfNumber(topFirst);
1412:                                widget.put(PdfName.TI, n);
1413:                                merged.put(PdfName.TI, n);
1414:                            }
1415:                            PdfDictionary appDic = (PdfDictionary) PdfReader
1416:                                    .getPdfObject(widget.get(PdfName.AP));
1417:                            if (appDic == null) {
1418:                                appDic = new PdfDictionary();
1419:                                widget.put(PdfName.AP, appDic);
1420:                                merged.put(PdfName.AP, appDic);
1421:                            }
1422:                            appDic.put(PdfName.N, app.getIndirectReference());
1423:                            writer.releaseTemplate(app);
1424:                        } else {
1425:                            widget.remove(PdfName.AP);
1426:                            merged.remove(PdfName.AP);
1427:                        }
1428:                        markUsed(widget);
1429:                    }
1430:                    return true;
1431:                } else if (PdfName.BTN.equals(type)) {
1432:                    PdfNumber ff = (PdfNumber) PdfReader
1433:                            .getPdfObject(((PdfDictionary) item.merged.get(0))
1434:                                    .get(PdfName.FF));
1435:                    int flags = 0;
1436:                    if (ff != null)
1437:                        flags = ff.intValue();
1438:                    if ((flags & PdfFormField.FF_PUSHBUTTON) != 0)
1439:                        return true;
1440:                    PdfName v = new PdfName(value);
1441:                    if ((flags & PdfFormField.FF_RADIO) == 0) {
1442:                        for (int idx = 0; idx < item.values.size(); ++idx) {
1443:                            ((PdfDictionary) item.values.get(idx)).put(
1444:                                    PdfName.V, v);
1445:                            markUsed((PdfDictionary) item.values.get(idx));
1446:                            PdfDictionary merged = (PdfDictionary) item.merged
1447:                                    .get(idx);
1448:                            merged.put(PdfName.V, v);
1449:                            merged.put(PdfName.AS, v);
1450:                            PdfDictionary widget = (PdfDictionary) item.widgets
1451:                                    .get(idx);
1452:                            if (isInAP(widget, v))
1453:                                widget.put(PdfName.AS, v);
1454:                            else
1455:                                widget.put(PdfName.AS, PdfName.Off);
1456:                            markUsed(widget);
1457:                        }
1458:                    } else {
1459:                        ArrayList lopt = new ArrayList();
1460:                        PdfObject opts = PdfReader
1461:                                .getPdfObject(((PdfDictionary) item.values
1462:                                        .get(0)).get(PdfName.OPT));
1463:                        if (opts != null && opts.isArray()) {
1464:                            ArrayList list = ((PdfArray) opts).getArrayList();
1465:                            for (int k = 0; k < list.size(); ++k) {
1466:                                PdfObject vv = PdfReader
1467:                                        .getPdfObject((PdfObject) list.get(k));
1468:                                if (vv != null && vv.isString())
1469:                                    lopt
1470:                                            .add(((PdfString) vv)
1471:                                                    .toUnicodeString());
1472:                                else
1473:                                    lopt.add(null);
1474:                            }
1475:                        }
1476:                        int vidx = lopt.indexOf(value);
1477:                        PdfName valt = null;
1478:                        PdfName vt;
1479:                        if (vidx >= 0) {
1480:                            vt = valt = new PdfName(String.valueOf(vidx));
1481:                        } else
1482:                            vt = v;
1483:                        for (int idx = 0; idx < item.values.size(); ++idx) {
1484:                            PdfDictionary merged = (PdfDictionary) item.merged
1485:                                    .get(idx);
1486:                            PdfDictionary widget = (PdfDictionary) item.widgets
1487:                                    .get(idx);
1488:                            markUsed((PdfDictionary) item.values.get(idx));
1489:                            if (valt != null) {
1490:                                PdfString ps = new PdfString(value,
1491:                                        PdfObject.TEXT_UNICODE);
1492:                                ((PdfDictionary) item.values.get(idx)).put(
1493:                                        PdfName.V, ps);
1494:                                merged.put(PdfName.V, ps);
1495:                            } else {
1496:                                ((PdfDictionary) item.values.get(idx)).put(
1497:                                        PdfName.V, v);
1498:                                merged.put(PdfName.V, v);
1499:                            }
1500:                            markUsed(widget);
1501:                            if (isInAP(widget, vt)) {
1502:                                merged.put(PdfName.AS, vt);
1503:                                widget.put(PdfName.AS, vt);
1504:                            } else {
1505:                                merged.put(PdfName.AS, PdfName.Off);
1506:                                widget.put(PdfName.AS, PdfName.Off);
1507:                            }
1508:                        }
1509:                    }
1510:                    return true;
1511:                }
1512:                return false;
1513:            }
1514:
1515:            boolean isInAP(PdfDictionary dic, PdfName check) {
1516:                PdfDictionary appDic = (PdfDictionary) PdfReader
1517:                        .getPdfObject(dic.get(PdfName.AP));
1518:                if (appDic == null)
1519:                    return false;
1520:                PdfDictionary NDic = (PdfDictionary) PdfReader
1521:                        .getPdfObject(appDic.get(PdfName.N));
1522:                return (NDic != null && NDic.get(check) != null);
1523:            }
1524:
1525:            /** Gets all the fields. The fields are keyed by the fully qualified field name and
1526:             * the value is an instance of <CODE>AcroFields.Item</CODE>.
1527:             * @return all the fields
1528:             */
1529:            public HashMap getFields() {
1530:                return fields;
1531:            }
1532:
1533:            /**
1534:             * Gets the field structure.
1535:             * @param name the name of the field
1536:             * @return the field structure or <CODE>null</CODE> if the field
1537:             * does not exist
1538:             */
1539:            public Item getFieldItem(String name) {
1540:                if (xfa.isXfaPresent()) {
1541:                    name = xfa.findFieldName(name, this );
1542:                    if (name == null)
1543:                        return null;
1544:                }
1545:                return (Item) fields.get(name);
1546:            }
1547:
1548:            /**
1549:             * Gets the long XFA translated name.
1550:             * @param name the name of the field
1551:             * @return the long field name
1552:             */
1553:            public String getTranslatedFieldName(String name) {
1554:                if (xfa.isXfaPresent()) {
1555:                    String namex = xfa.findFieldName(name, this );
1556:                    if (namex != null)
1557:                        name = namex;
1558:                }
1559:                return name;
1560:            }
1561:
1562:            /**
1563:             * Gets the field box positions in the document. The return is an array of <CODE>float</CODE>
1564:             * multiple of 5. For each of this groups the values are: [page, llx, lly, urx,
1565:             * ury]. The coordinates have the page rotation in consideration.
1566:             * @param name the field name
1567:             * @return the positions or <CODE>null</CODE> if field does not exist
1568:             */
1569:            public float[] getFieldPositions(String name) {
1570:                Item item = getFieldItem(name);
1571:                if (item == null)
1572:                    return null;
1573:                float ret[] = new float[item.page.size() * 5];
1574:                int ptr = 0;
1575:                for (int k = 0; k < item.page.size(); ++k) {
1576:                    try {
1577:                        PdfDictionary wd = (PdfDictionary) item.widgets.get(k);
1578:                        PdfArray rect = (PdfArray) wd.get(PdfName.RECT);
1579:                        if (rect == null)
1580:                            continue;
1581:                        Rectangle r = PdfReader.getNormalizedRectangle(rect);
1582:                        int page = ((Integer) item.page.get(k)).intValue();
1583:                        int rotation = reader.getPageRotation(page);
1584:                        ret[ptr++] = page;
1585:                        if (rotation != 0) {
1586:                            Rectangle pageSize = reader.getPageSize(page);
1587:                            switch (rotation) {
1588:                            case 270:
1589:                                r = new Rectangle(pageSize.getTop()
1590:                                        - r.getBottom(), r.getLeft(), pageSize
1591:                                        .getTop()
1592:                                        - r.getTop(), r.getRight());
1593:                                break;
1594:                            case 180:
1595:                                r = new Rectangle(pageSize.getRight()
1596:                                        - r.getLeft(), pageSize.getTop()
1597:                                        - r.getBottom(), pageSize.getRight()
1598:                                        - r.getRight(), pageSize.getTop()
1599:                                        - r.getTop());
1600:                                break;
1601:                            case 90:
1602:                                r = new Rectangle(r.getBottom(), pageSize
1603:                                        .getRight()
1604:                                        - r.getLeft(), r.getTop(), pageSize
1605:                                        .getRight()
1606:                                        - r.getRight());
1607:                                break;
1608:                            }
1609:                            r.normalize();
1610:                        }
1611:                        ret[ptr++] = r.getLeft();
1612:                        ret[ptr++] = r.getBottom();
1613:                        ret[ptr++] = r.getRight();
1614:                        ret[ptr++] = r.getTop();
1615:                    } catch (Exception e) {
1616:                        // empty on purpose
1617:                    }
1618:                }
1619:                if (ptr < ret.length) {
1620:                    float ret2[] = new float[ptr];
1621:                    System.arraycopy(ret, 0, ret2, 0, ptr);
1622:                    return ret2;
1623:                }
1624:                return ret;
1625:            }
1626:
1627:            private int removeRefFromArray(PdfArray array, PdfObject refo) {
1628:                ArrayList ar = array.getArrayList();
1629:                if (refo == null || !refo.isIndirect())
1630:                    return ar.size();
1631:                PdfIndirectReference ref = (PdfIndirectReference) refo;
1632:                for (int j = 0; j < ar.size(); ++j) {
1633:                    PdfObject obj = (PdfObject) ar.get(j);
1634:                    if (!obj.isIndirect())
1635:                        continue;
1636:                    if (((PdfIndirectReference) obj).getNumber() == ref
1637:                            .getNumber())
1638:                        ar.remove(j--);
1639:                }
1640:                return ar.size();
1641:            }
1642:
1643:            /**
1644:             * Removes all the fields from <CODE>page</CODE>.
1645:             * @param page the page to remove the fields from
1646:             * @return <CODE>true</CODE> if any field was removed, <CODE>false otherwise</CODE>
1647:             */
1648:            public boolean removeFieldsFromPage(int page) {
1649:                if (page < 1)
1650:                    return false;
1651:                String names[] = new String[fields.size()];
1652:                fields.keySet().toArray(names);
1653:                boolean found = false;
1654:                for (int k = 0; k < names.length; ++k) {
1655:                    boolean fr = removeField(names[k], page);
1656:                    found = (found || fr);
1657:                }
1658:                return found;
1659:            }
1660:
1661:            /**
1662:             * Removes a field from the document. If page equals -1 all the fields with this
1663:             * <CODE>name</CODE> are removed from the document otherwise only the fields in
1664:             * that particular page are removed.
1665:             * @param name the field name
1666:             * @param page the page to remove the field from or -1 to remove it from all the pages
1667:             * @return <CODE>true</CODE> if the field exists, <CODE>false otherwise</CODE>
1668:             */
1669:            public boolean removeField(String name, int page) {
1670:                Item item = getFieldItem(name);
1671:                if (item == null)
1672:                    return false;
1673:                PdfDictionary acroForm = (PdfDictionary) PdfReader
1674:                        .getPdfObject(
1675:                                reader.getCatalog().get(PdfName.ACROFORM),
1676:                                reader.getCatalog());
1677:
1678:                if (acroForm == null)
1679:                    return false;
1680:                PdfArray arrayf = (PdfArray) PdfReader.getPdfObject(acroForm
1681:                        .get(PdfName.FIELDS), acroForm);
1682:                if (arrayf == null)
1683:                    return false;
1684:                for (int k = 0; k < item.widget_refs.size(); ++k) {
1685:                    int pageV = ((Integer) item.page.get(k)).intValue();
1686:                    if (page != -1 && page != pageV)
1687:                        continue;
1688:                    PdfIndirectReference ref = (PdfIndirectReference) item.widget_refs
1689:                            .get(k);
1690:                    PdfDictionary wd = (PdfDictionary) PdfReader
1691:                            .getPdfObject(ref);
1692:                    PdfDictionary pageDic = reader.getPageN(pageV);
1693:                    PdfArray annots = (PdfArray) PdfReader.getPdfObject(pageDic
1694:                            .get(PdfName.ANNOTS), pageDic);
1695:                    if (annots != null) {
1696:                        if (removeRefFromArray(annots, ref) == 0) {
1697:                            pageDic.remove(PdfName.ANNOTS);
1698:                            markUsed(pageDic);
1699:                        } else
1700:                            markUsed(annots);
1701:                    }
1702:                    PdfReader.killIndirect(ref);
1703:                    PdfIndirectReference kid = ref;
1704:                    while ((ref = (PdfIndirectReference) wd.get(PdfName.PARENT)) != null) {
1705:                        wd = (PdfDictionary) PdfReader.getPdfObject(ref);
1706:                        PdfArray kids = (PdfArray) PdfReader.getPdfObject(wd
1707:                                .get(PdfName.KIDS));
1708:                        if (removeRefFromArray(kids, kid) != 0)
1709:                            break;
1710:                        kid = ref;
1711:                        PdfReader.killIndirect(ref);
1712:                    }
1713:                    if (ref == null) {
1714:                        removeRefFromArray(arrayf, kid);
1715:                        markUsed(arrayf);
1716:                    }
1717:                    if (page != -1) {
1718:                        item.merged.remove(k);
1719:                        item.page.remove(k);
1720:                        item.values.remove(k);
1721:                        item.widget_refs.remove(k);
1722:                        item.widgets.remove(k);
1723:                        --k;
1724:                    }
1725:                }
1726:                if (page == -1 || item.merged.size() == 0)
1727:                    fields.remove(name);
1728:                return true;
1729:            }
1730:
1731:            /**
1732:             * Removes a field from the document.
1733:             * @param name the field name
1734:             * @return <CODE>true</CODE> if the field exists, <CODE>false otherwise</CODE>
1735:             */
1736:            public boolean removeField(String name) {
1737:                return removeField(name, -1);
1738:            }
1739:
1740:            /** Gets the property generateAppearances.
1741:             * @return the property generateAppearances
1742:             */
1743:            public boolean isGenerateAppearances() {
1744:                return this .generateAppearances;
1745:            }
1746:
1747:            /** Sets the option to generate appearances. Not generating apperances
1748:             * will speed-up form filling but the results can be
1749:             * unexpected in Acrobat. Don't use it unless your environment is well
1750:             * controlled. The default is <CODE>true</CODE>.
1751:             * @param generateAppearances the option to generate appearances
1752:             */
1753:            public void setGenerateAppearances(boolean generateAppearances) {
1754:                this .generateAppearances = generateAppearances;
1755:                PdfDictionary top = (PdfDictionary) PdfReader
1756:                        .getPdfObject(reader.getCatalog().get(PdfName.ACROFORM));
1757:                if (generateAppearances)
1758:                    top.remove(PdfName.NEEDAPPEARANCES);
1759:                else
1760:                    top.put(PdfName.NEEDAPPEARANCES, PdfBoolean.PDFTRUE);
1761:            }
1762:
1763:            /** The field representations for retrieval and modification. */
1764:            public static class Item {
1765:                /** An array of <CODE>PdfDictionary</CODE> where the value tag /V
1766:                 * is present.
1767:                 */
1768:                public ArrayList values = new ArrayList();
1769:                /** An array of <CODE>PdfDictionary</CODE> with the widgets.
1770:                 */
1771:                public ArrayList widgets = new ArrayList();
1772:                /** An array of <CODE>PdfDictionary</CODE> with the widget references.
1773:                 */
1774:                public ArrayList widget_refs = new ArrayList();
1775:                /** An array of <CODE>PdfDictionary</CODE> with all the field
1776:                 * and widget tags merged.
1777:                 */
1778:                public ArrayList merged = new ArrayList();
1779:                /** An array of <CODE>Integer</CODE> with the page numbers where
1780:                 * the widgets are displayed.
1781:                 */
1782:                public ArrayList page = new ArrayList();
1783:                /** An array of <CODE>Integer</CODE> with the tab order of the field in the page.
1784:                 */
1785:                public ArrayList tabOrder = new ArrayList();
1786:            }
1787:
1788:            private static class InstHit {
1789:                IntHashtable hits;
1790:
1791:                public InstHit(int inst[]) {
1792:                    if (inst == null)
1793:                        return;
1794:                    hits = new IntHashtable();
1795:                    for (int k = 0; k < inst.length; ++k)
1796:                        hits.put(inst[k], 1);
1797:                }
1798:
1799:                public boolean isHit(int n) {
1800:                    if (hits == null)
1801:                        return true;
1802:                    return hits.containsKey(n);
1803:                }
1804:            }
1805:
1806:            /**
1807:             * Gets the field names that have signatures and are signed.
1808:             * @return the field names that have signatures and are signed
1809:             */
1810:            public ArrayList getSignatureNames() {
1811:                if (sigNames != null)
1812:                    return new ArrayList(sigNames.keySet());
1813:                sigNames = new HashMap();
1814:                ArrayList sorter = new ArrayList();
1815:                for (Iterator it = fields.entrySet().iterator(); it.hasNext();) {
1816:                    Map.Entry entry = (Map.Entry) it.next();
1817:                    Item item = (Item) entry.getValue();
1818:                    PdfDictionary merged = (PdfDictionary) item.merged.get(0);
1819:                    if (!PdfName.SIG.equals(merged.get(PdfName.FT)))
1820:                        continue;
1821:                    PdfObject vo = PdfReader
1822:                            .getPdfObject(merged.get(PdfName.V));
1823:                    if (vo == null || vo.type() != PdfObject.DICTIONARY)
1824:                        continue;
1825:                    PdfDictionary v = (PdfDictionary) vo;
1826:                    PdfObject contents = v.get(PdfName.CONTENTS);
1827:                    if (contents == null || contents.type() != PdfObject.STRING)
1828:                        continue;
1829:                    PdfObject ro = v.get(PdfName.BYTERANGE);
1830:                    if (ro == null || ro.type() != PdfObject.ARRAY)
1831:                        continue;
1832:                    ArrayList ra = ((PdfArray) ro).getArrayList();
1833:                    if (ra.size() < 2)
1834:                        continue;
1835:                    int length = ((PdfNumber) ra.get(ra.size() - 1)).intValue()
1836:                            + ((PdfNumber) ra.get(ra.size() - 2)).intValue();
1837:                    sorter.add(new Object[] { entry.getKey(),
1838:                            new int[] { length, 0 } });
1839:                }
1840:                Collections.sort(sorter, new AcroFields.SorterComparator());
1841:                if (!sorter.isEmpty()) {
1842:                    if (((int[]) ((Object[]) sorter.get(sorter.size() - 1))[1])[0] == reader
1843:                            .getFileLength())
1844:                        totalRevisions = sorter.size();
1845:                    else
1846:                        totalRevisions = sorter.size() + 1;
1847:                    for (int k = 0; k < sorter.size(); ++k) {
1848:                        Object objs[] = (Object[]) sorter.get(k);
1849:                        String name = (String) objs[0];
1850:                        int p[] = (int[]) objs[1];
1851:                        p[1] = k + 1;
1852:                        sigNames.put(name, p);
1853:                    }
1854:                }
1855:                return new ArrayList(sigNames.keySet());
1856:            }
1857:
1858:            /**
1859:             * Gets the field names that have blank signatures.
1860:             * @return the field names that have blank signatures
1861:             */
1862:            public ArrayList getBlankSignatureNames() {
1863:                getSignatureNames();
1864:                ArrayList sigs = new ArrayList();
1865:                for (Iterator it = fields.entrySet().iterator(); it.hasNext();) {
1866:                    Map.Entry entry = (Map.Entry) it.next();
1867:                    Item item = (Item) entry.getValue();
1868:                    PdfDictionary merged = (PdfDictionary) item.merged.get(0);
1869:                    if (!PdfName.SIG.equals(merged.get(PdfName.FT)))
1870:                        continue;
1871:                    if (sigNames.containsKey(entry.getKey()))
1872:                        continue;
1873:                    sigs.add(entry.getKey());
1874:                }
1875:                return sigs;
1876:            }
1877:
1878:            /**
1879:             * Gets the signature dictionary, the one keyed by /V.
1880:             * @param name the field name
1881:             * @return the signature dictionary keyed by /V or <CODE>null</CODE> if the field is not
1882:             * a signature
1883:             */
1884:            public PdfDictionary getSignatureDictionary(String name) {
1885:                getSignatureNames();
1886:                name = getTranslatedFieldName(name);
1887:                if (!sigNames.containsKey(name))
1888:                    return null;
1889:                Item item = (Item) fields.get(name);
1890:                PdfDictionary merged = (PdfDictionary) item.merged.get(0);
1891:                return (PdfDictionary) PdfReader.getPdfObject(merged
1892:                        .get(PdfName.V));
1893:            }
1894:
1895:            /**
1896:             * Checks is the signature covers the entire document or just part of it.
1897:             * @param name the signature field name
1898:             * @return <CODE>true</CODE> if the signature covers the entire document,
1899:             * <CODE>false</CODE> otherwise
1900:             */
1901:            public boolean signatureCoversWholeDocument(String name) {
1902:                getSignatureNames();
1903:                name = getTranslatedFieldName(name);
1904:                if (!sigNames.containsKey(name))
1905:                    return false;
1906:                return ((int[]) sigNames.get(name))[0] == reader
1907:                        .getFileLength();
1908:            }
1909:
1910:            /**
1911:             * Verifies a signature. An example usage is:
1912:             * <p>
1913:             * <pre>
1914:             * KeyStore kall = PdfPKCS7.loadCacertsKeyStore();
1915:             * PdfReader reader = new PdfReader("my_signed_doc.pdf");
1916:             * AcroFields af = reader.getAcroFields();
1917:             * ArrayList names = af.getSignatureNames();
1918:             * for (int k = 0; k &lt; names.size(); ++k) {
1919:             *    String name = (String)names.get(k);
1920:             *    System.out.println("Signature name: " + name);
1921:             *    System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
1922:             *    PdfPKCS7 pk = af.verifySignature(name);
1923:             *    Calendar cal = pk.getSignDate();
1924:             *    Certificate pkc[] = pk.getCertificates();
1925:             *    System.out.println("Subject: " + PdfPKCS7.getSubjectFields(pk.getSigningCertificate()));
1926:             *    System.out.println("Document modified: " + !pk.verify());
1927:             *    Object fails[] = PdfPKCS7.verifyCertificates(pkc, kall, null, cal);
1928:             *    if (fails == null)
1929:             *        System.out.println("Certificates verified against the KeyStore");
1930:             *    else
1931:             *        System.out.println("Certificate failed: " + fails[1]);
1932:             * }
1933:             * </pre>
1934:             * @param name the signature field name
1935:             * @return a <CODE>PdfPKCS7</CODE> class to continue the verification
1936:             */
1937:            public PdfPKCS7 verifySignature(String name) {
1938:                return verifySignature(name, null);
1939:            }
1940:
1941:            /**
1942:             * Verifies a signature. An example usage is:
1943:             * <p>
1944:             * <pre>
1945:             * KeyStore kall = PdfPKCS7.loadCacertsKeyStore();
1946:             * PdfReader reader = new PdfReader("my_signed_doc.pdf");
1947:             * AcroFields af = reader.getAcroFields();
1948:             * ArrayList names = af.getSignatureNames();
1949:             * for (int k = 0; k &lt; names.size(); ++k) {
1950:             *    String name = (String)names.get(k);
1951:             *    System.out.println("Signature name: " + name);
1952:             *    System.out.println("Signature covers whole document: " + af.signatureCoversWholeDocument(name));
1953:             *    PdfPKCS7 pk = af.verifySignature(name);
1954:             *    Calendar cal = pk.getSignDate();
1955:             *    Certificate pkc[] = pk.getCertificates();
1956:             *    System.out.println("Subject: " + PdfPKCS7.getSubjectFields(pk.getSigningCertificate()));
1957:             *    System.out.println("Document modified: " + !pk.verify());
1958:             *    Object fails[] = PdfPKCS7.verifyCertificates(pkc, kall, null, cal);
1959:             *    if (fails == null)
1960:             *        System.out.println("Certificates verified against the KeyStore");
1961:             *    else
1962:             *        System.out.println("Certificate failed: " + fails[1]);
1963:             * }
1964:             * </pre>
1965:             * @param name the signature field name
1966:             * @param provider the provider or <code>null</code> for the default provider
1967:             * @return a <CODE>PdfPKCS7</CODE> class to continue the verification
1968:             */
1969:            public PdfPKCS7 verifySignature(String name, String provider) {
1970:                PdfDictionary v = getSignatureDictionary(name);
1971:                if (v == null)
1972:                    return null;
1973:                try {
1974:                    PdfName sub = (PdfName) PdfReader.getPdfObject(v
1975:                            .get(PdfName.SUBFILTER));
1976:                    PdfString contents = (PdfString) PdfReader.getPdfObject(v
1977:                            .get(PdfName.CONTENTS));
1978:                    PdfPKCS7 pk = null;
1979:                    if (sub.equals(PdfName.ADBE_X509_RSA_SHA1)) {
1980:                        PdfString cert = (PdfString) PdfReader.getPdfObject(v
1981:                                .get(PdfName.CERT));
1982:                        pk = new PdfPKCS7(contents.getOriginalBytes(), cert
1983:                                .getBytes(), provider);
1984:                    } else
1985:                        pk = new PdfPKCS7(contents.getOriginalBytes(), provider);
1986:                    updateByteRange(pk, v);
1987:                    PdfString str = (PdfString) PdfReader.getPdfObject(v
1988:                            .get(PdfName.M));
1989:                    if (str != null)
1990:                        pk.setSignDate(PdfDate.decode(str.toString()));
1991:                    PdfObject obj = PdfReader.getPdfObject(v.get(PdfName.NAME));
1992:                    if (obj != null) {
1993:                        if (obj.isString())
1994:                            pk.setSignName(((PdfString) obj).toUnicodeString());
1995:                        else if (obj.isName())
1996:                            pk.setSignName(PdfName.decodeName(obj.toString()));
1997:                    }
1998:                    str = (PdfString) PdfReader.getPdfObject(v
1999:                            .get(PdfName.REASON));
2000:                    if (str != null)
2001:                        pk.setReason(str.toUnicodeString());
2002:                    str = (PdfString) PdfReader.getPdfObject(v
2003:                            .get(PdfName.LOCATION));
2004:                    if (str != null)
2005:                        pk.setLocation(str.toUnicodeString());
2006:                    return pk;
2007:                } catch (Exception e) {
2008:                    throw new ExceptionConverter(e);
2009:                }
2010:            }
2011:
2012:            private void updateByteRange(PdfPKCS7 pkcs7, PdfDictionary v) {
2013:                PdfArray b = (PdfArray) PdfReader.getPdfObject(v
2014:                        .get(PdfName.BYTERANGE));
2015:                RandomAccessFileOrArray rf = reader.getSafeFile();
2016:                try {
2017:                    rf.reOpen();
2018:                    byte buf[] = new byte[8192];
2019:                    ArrayList ar = b.getArrayList();
2020:                    for (int k = 0; k < ar.size(); ++k) {
2021:                        int start = ((PdfNumber) ar.get(k)).intValue();
2022:                        int length = ((PdfNumber) ar.get(++k)).intValue();
2023:                        rf.seek(start);
2024:                        while (length > 0) {
2025:                            int rd = rf.read(buf, 0, Math.min(length,
2026:                                    buf.length));
2027:                            if (rd <= 0)
2028:                                break;
2029:                            length -= rd;
2030:                            pkcs7.update(buf, 0, rd);
2031:                        }
2032:                    }
2033:                } catch (Exception e) {
2034:                    throw new ExceptionConverter(e);
2035:                } finally {
2036:                    try {
2037:                        rf.close();
2038:                    } catch (Exception e) {
2039:                    }
2040:                }
2041:            }
2042:
2043:            private void markUsed(PdfObject obj) {
2044:                if (!append)
2045:                    return;
2046:                ((PdfStamperImp) writer).markUsed(obj);
2047:            }
2048:
2049:            /**
2050:             * Gets the total number of revisions this document has.
2051:             * @return the total number of revisions
2052:             */
2053:            public int getTotalRevisions() {
2054:                getSignatureNames();
2055:                return this .totalRevisions;
2056:            }
2057:
2058:            /**
2059:             * Gets this <CODE>field</CODE> revision.
2060:             * @param field the signature field name
2061:             * @return the revision or zero if it's not a signature field
2062:             */
2063:            public int getRevision(String field) {
2064:                getSignatureNames();
2065:                field = getTranslatedFieldName(field);
2066:                if (!sigNames.containsKey(field))
2067:                    return 0;
2068:                return ((int[]) sigNames.get(field))[1];
2069:            }
2070:
2071:            /**
2072:             * Extracts a revision from the document.
2073:             * @param field the signature field name
2074:             * @return an <CODE>InputStream</CODE> covering the revision. Returns <CODE>null</CODE> if
2075:             * it's not a signature field
2076:             * @throws IOException on error
2077:             */
2078:            public InputStream extractRevision(String field) throws IOException {
2079:                getSignatureNames();
2080:                field = getTranslatedFieldName(field);
2081:                if (!sigNames.containsKey(field))
2082:                    return null;
2083:                int length = ((int[]) sigNames.get(field))[0];
2084:                RandomAccessFileOrArray raf = reader.getSafeFile();
2085:                raf.reOpen();
2086:                raf.seek(0);
2087:                return new RevisionStream(raf, length);
2088:            }
2089:
2090:            /**
2091:             * Gets the appearances cache.
2092:             * @return the appearances cache
2093:             */
2094:            public HashMap getFieldCache() {
2095:                return this .fieldCache;
2096:            }
2097:
2098:            /**
2099:             * Sets a cache for field appearances. Parsing the existing PDF to
2100:             * create a new TextField is time expensive. For those tasks that repeatedly
2101:             * fill the same PDF with different field values the use of the cache has dramatic
2102:             * speed advantages. An example usage:
2103:             * <p>
2104:             * <pre>
2105:             * String pdfFile = ...;// the pdf file used as template
2106:             * ArrayList xfdfFiles = ...;// the xfdf file names
2107:             * ArrayList pdfOutFiles = ...;// the output file names, one for each element in xpdfFiles
2108:             * HashMap cache = new HashMap();// the appearances cache
2109:             * PdfReader originalReader = new PdfReader(pdfFile);
2110:             * for (int k = 0; k &lt; xfdfFiles.size(); ++k) {
2111:             *    PdfReader reader = new PdfReader(originalReader);
2112:             *    XfdfReader xfdf = new XfdfReader((String)xfdfFiles.get(k));
2113:             *    PdfStamper stp = new PdfStamper(reader, new FileOutputStream((String)pdfOutFiles.get(k)));
2114:             *    AcroFields af = stp.getAcroFields();
2115:             *    af.setFieldCache(cache);
2116:             *    af.setFields(xfdf);
2117:             *    stp.close();
2118:             * }
2119:             * </pre>
2120:             * @param fieldCache an HasMap that will carry the cached appearances
2121:             */
2122:            public void setFieldCache(HashMap fieldCache) {
2123:                this .fieldCache = fieldCache;
2124:            }
2125:
2126:            /**
2127:             * Sets extra margins in text fields to better mimic the Acrobat layout.
2128:             * @param extraMarginLeft the extra marging left
2129:             * @param extraMarginTop the extra margin top
2130:             */
2131:            public void setExtraMargin(float extraMarginLeft,
2132:                    float extraMarginTop) {
2133:                this .extraMarginLeft = extraMarginLeft;
2134:                this .extraMarginTop = extraMarginTop;
2135:            }
2136:
2137:            /**
2138:             * Adds a substitution font to the list. The fonts in this list will be used if the original
2139:             * font doesn't contain the needed glyphs.
2140:             * @param font the font
2141:             */
2142:            public void addSubstitutionFont(BaseFont font) {
2143:                if (substitutionFonts == null)
2144:                    substitutionFonts = new ArrayList();
2145:                substitutionFonts.add(font);
2146:            }
2147:
2148:            private static final HashMap stdFieldFontNames = new HashMap();
2149:
2150:            /**
2151:             * Holds value of property totalRevisions.
2152:             */
2153:            private int totalRevisions;
2154:
2155:            /**
2156:             * Holds value of property fieldCache.
2157:             */
2158:            private HashMap fieldCache;
2159:
2160:            static {
2161:                stdFieldFontNames.put("CoBO",
2162:                        new String[] { "Courier-BoldOblique" });
2163:                stdFieldFontNames.put("CoBo", new String[] { "Courier-Bold" });
2164:                stdFieldFontNames.put("CoOb",
2165:                        new String[] { "Courier-Oblique" });
2166:                stdFieldFontNames.put("Cour", new String[] { "Courier" });
2167:                stdFieldFontNames.put("HeBO",
2168:                        new String[] { "Helvetica-BoldOblique" });
2169:                stdFieldFontNames
2170:                        .put("HeBo", new String[] { "Helvetica-Bold" });
2171:                stdFieldFontNames.put("HeOb",
2172:                        new String[] { "Helvetica-Oblique" });
2173:                stdFieldFontNames.put("Helv", new String[] { "Helvetica" });
2174:                stdFieldFontNames.put("Symb", new String[] { "Symbol" });
2175:                stdFieldFontNames.put("TiBI",
2176:                        new String[] { "Times-BoldItalic" });
2177:                stdFieldFontNames.put("TiBo", new String[] { "Times-Bold" });
2178:                stdFieldFontNames.put("TiIt", new String[] { "Times-Italic" });
2179:                stdFieldFontNames.put("TiRo", new String[] { "Times-Roman" });
2180:                stdFieldFontNames.put("ZaDb", new String[] { "ZapfDingbats" });
2181:                stdFieldFontNames.put("HySm", new String[] {
2182:                        "HYSMyeongJo-Medium", "UniKS-UCS2-H" });
2183:                stdFieldFontNames.put("HyGo", new String[] { "HYGoThic-Medium",
2184:                        "UniKS-UCS2-H" });
2185:                stdFieldFontNames.put("KaGo", new String[] { "HeiseiKakuGo-W5",
2186:                        "UniKS-UCS2-H" });
2187:                stdFieldFontNames.put("KaMi", new String[] { "HeiseiMin-W3",
2188:                        "UniJIS-UCS2-H" });
2189:                stdFieldFontNames.put("MHei", new String[] { "MHei-Medium",
2190:                        "UniCNS-UCS2-H" });
2191:                stdFieldFontNames.put("MSun", new String[] { "MSung-Light",
2192:                        "UniCNS-UCS2-H" });
2193:                stdFieldFontNames.put("STSo", new String[] { "STSong-Light",
2194:                        "UniGB-UCS2-H" });
2195:            }
2196:
2197:            private static class RevisionStream extends InputStream {
2198:                private byte b[] = new byte[1];
2199:                private RandomAccessFileOrArray raf;
2200:                private int length;
2201:                private int rangePosition = 0;
2202:                private boolean closed;
2203:
2204:                private RevisionStream(RandomAccessFileOrArray raf, int length) {
2205:                    this .raf = raf;
2206:                    this .length = length;
2207:                }
2208:
2209:                public int read() throws IOException {
2210:                    int n = read(b);
2211:                    if (n != 1)
2212:                        return -1;
2213:                    return b[0] & 0xff;
2214:                }
2215:
2216:                public int read(byte[] b, int off, int len) throws IOException {
2217:                    if (b == null) {
2218:                        throw new NullPointerException();
2219:                    } else if ((off < 0) || (off > b.length) || (len < 0)
2220:                            || ((off + len) > b.length) || ((off + len) < 0)) {
2221:                        throw new IndexOutOfBoundsException();
2222:                    } else if (len == 0) {
2223:                        return 0;
2224:                    }
2225:                    if (rangePosition >= length) {
2226:                        close();
2227:                        return -1;
2228:                    }
2229:                    int elen = Math.min(len, length - rangePosition);
2230:                    raf.readFully(b, off, elen);
2231:                    rangePosition += elen;
2232:                    return elen;
2233:                }
2234:
2235:                public void close() throws IOException {
2236:                    if (!closed) {
2237:                        raf.close();
2238:                        closed = true;
2239:                    }
2240:                }
2241:            }
2242:
2243:            private static class SorterComparator implements  Comparator {
2244:                public int compare(Object o1, Object o2) {
2245:                    int n1 = ((int[]) ((Object[]) o1)[1])[0];
2246:                    int n2 = ((int[]) ((Object[]) o2)[1])[0];
2247:                    return n1 - n2;
2248:                }
2249:            }
2250:
2251:            /**
2252:             * Gets the list of substitution fonts. The list is composed of <CODE>BaseFont</CODE> and can be <CODE>null</CODE>. The fonts in this list will be used if the original
2253:             * font doesn't contain the needed glyphs.
2254:             * @return the list
2255:             */
2256:            public ArrayList getSubstitutionFonts() {
2257:                return substitutionFonts;
2258:            }
2259:
2260:            /**
2261:             * Sets a list of substitution fonts. The list is composed of <CODE>BaseFont</CODE> and can also be <CODE>null</CODE>. The fonts in this list will be used if the original
2262:             * font doesn't contain the needed glyphs.
2263:             * @param substitutionFonts the list
2264:             */
2265:            public void setSubstitutionFonts(ArrayList substitutionFonts) {
2266:                this .substitutionFonts = substitutionFonts;
2267:            }
2268:
2269:            /**
2270:             * Gets the XFA form processor.
2271:             * @return the XFA form processor
2272:             */
2273:            public XfaForm getXfa() {
2274:                return xfa;
2275:            }
2276:
2277:            private static final PdfName[] buttonRemove = { PdfName.MK,
2278:                    PdfName.F, PdfName.FF, PdfName.Q, PdfName.BS,
2279:                    PdfName.BORDER };
2280:
2281:            /**
2282:             * Creates a new pushbutton from an existing field. This pushbutton can be changed and be used to replace 
2283:             * an existing one, with the same name or other name, as long is it is in the same document. To replace an existing pushbutton
2284:             * call {@link #replacePushbuttonField(String,PdfFormField)}.
2285:             * @param field the field name that should be a pushbutton
2286:             * @return a new pushbutton or <CODE>null</CODE> if the field is not a pushbutton
2287:             */
2288:            public PushbuttonField getNewPushbuttonFromField(String field) {
2289:                try {
2290:                    if (getFieldType(field) != FIELD_TYPE_PUSHBUTTON)
2291:                        return null;
2292:                    float[] pos = getFieldPositions(field);
2293:                    Rectangle box = new Rectangle(pos[1], pos[2], pos[3],
2294:                            pos[4]);
2295:                    PushbuttonField newButton = new PushbuttonField(writer,
2296:                            box, null);
2297:                    Item item = getFieldItem(field);
2298:                    PdfDictionary dic = (PdfDictionary) item.merged.get(0);
2299:                    decodeGenericDictionary(dic, newButton);
2300:                    PdfDictionary mk = (PdfDictionary) PdfReader
2301:                            .getPdfObject(dic.get(PdfName.MK));
2302:                    if (mk != null) {
2303:                        PdfString text = (PdfString) PdfReader.getPdfObject(mk
2304:                                .get(PdfName.CA));
2305:                        if (text != null)
2306:                            newButton.setText(text.toUnicodeString());
2307:                        PdfNumber tp = (PdfNumber) PdfReader.getPdfObject(mk
2308:                                .get(PdfName.TP));
2309:                        if (tp != null)
2310:                            newButton.setLayout(tp.intValue() + 1);
2311:                        PdfDictionary ifit = (PdfDictionary) PdfReader
2312:                                .getPdfObject(mk.get(PdfName.IF));
2313:                        if (ifit != null) {
2314:                            PdfName sw = (PdfName) PdfReader.getPdfObject(ifit
2315:                                    .get(PdfName.SW));
2316:                            if (sw != null) {
2317:                                int scale = PushbuttonField.SCALE_ICON_ALWAYS;
2318:                                if (sw.equals(PdfName.B))
2319:                                    scale = PushbuttonField.SCALE_ICON_IS_TOO_BIG;
2320:                                else if (sw.equals(PdfName.S))
2321:                                    scale = PushbuttonField.SCALE_ICON_IS_TOO_SMALL;
2322:                                else if (sw.equals(PdfName.N))
2323:                                    scale = PushbuttonField.SCALE_ICON_NEVER;
2324:                                newButton.setScaleIcon(scale);
2325:                            }
2326:                            sw = (PdfName) PdfReader.getPdfObject(ifit
2327:                                    .get(PdfName.S));
2328:                            if (sw != null) {
2329:                                if (sw.equals(PdfName.A))
2330:                                    newButton.setProportionalIcon(false);
2331:                            }
2332:                            PdfArray aj = (PdfArray) PdfReader
2333:                                    .getPdfObject(ifit.get(PdfName.A));
2334:                            if (aj != null && aj.size() == 2) {
2335:                                float left = ((PdfNumber) PdfReader
2336:                                        .getPdfObject((PdfObject) aj
2337:                                                .getArrayList().get(0)))
2338:                                        .floatValue();
2339:                                float bottom = ((PdfNumber) PdfReader
2340:                                        .getPdfObject((PdfObject) aj
2341:                                                .getArrayList().get(1)))
2342:                                        .floatValue();
2343:                                newButton.setIconHorizontalAdjustment(left);
2344:                                newButton.setIconVerticalAdjustment(bottom);
2345:                            }
2346:                            PdfObject fb = PdfReader.getPdfObject(ifit
2347:                                    .get(PdfName.FB));
2348:                            if (fb != null && fb.toString().equals("true"))
2349:                                newButton.setIconFitToBounds(true);
2350:                        }
2351:                        PdfObject i = mk.get(PdfName.I);
2352:                        if (i != null && i.isIndirect())
2353:                            newButton.setIconReference((PRIndirectReference) i);
2354:                    }
2355:                    return newButton;
2356:                } catch (Exception e) {
2357:                    throw new ExceptionConverter(e);
2358:                }
2359:            }
2360:
2361:            /**
2362:             * Replaces the field with a new pushbutton. The pushbutton can be created with
2363:             * {@link #getNewPushbuttonFromField(String)} from the same document or it can be a
2364:             * generic PdfFormField of the type pushbutton.
2365:             * @param field the field name
2366:             * @param button the <CODE>PdfFormField</CODE> representing the pushbutton
2367:             * @return <CODE>true</CODE> if the field was replaced, <CODE>false</CODE> if the field
2368:             * was not a pushbutton
2369:             */
2370:            public boolean replacePushbuttonField(String field,
2371:                    PdfFormField button) {
2372:                if (getFieldType(field) != FIELD_TYPE_PUSHBUTTON)
2373:                    return false;
2374:                Item item = getFieldItem(field);
2375:                PdfDictionary merged = (PdfDictionary) item.merged.get(0);
2376:                PdfDictionary values = (PdfDictionary) item.values.get(0);
2377:                PdfDictionary widgets = (PdfDictionary) item.widgets.get(0);
2378:                for (int k = 0; k < buttonRemove.length; ++k) {
2379:                    merged.remove(buttonRemove[k]);
2380:                    values.remove(buttonRemove[k]);
2381:                    widgets.remove(buttonRemove[k]);
2382:                }
2383:                for (Iterator it = button.getKeys().iterator(); it.hasNext();) {
2384:                    PdfName key = (PdfName) it.next();
2385:                    if (key.equals(PdfName.T) || key.equals(PdfName.RECT))
2386:                        continue;
2387:                    merged.put(key, button.get(key));
2388:                    widgets.put(key, button.get(key));
2389:                }
2390:                return true;
2391:            }
2392:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.