001: /*
002: * $Id: PdfCopyFieldsImp.java 2869 2007-07-10 15:20:20Z psoares33 $
003: * $Name$
004: * Copyright 2004 by Paulo Soares.
005: *
006: * The contents of this file are subject to the Mozilla Public License Version 1.1
007: * (the "License"); you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the License.
013: *
014: * The Original Code is 'iText, a free JAVA-PDF library'.
015: *
016: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
017: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
018: * All Rights Reserved.
019: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
020: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
021: *
022: * Contributor(s): all the names of the contributors are added in the source code
023: * where applicable.
024: *
025: * Alternatively, the contents of this file may be used under the terms of the
026: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
027: * provisions of LGPL are applicable instead of those above. If you wish to
028: * allow use of your version of this file only under the terms of the LGPL
029: * License and not to allow others to use your version of this file under
030: * the MPL, indicate your decision by deleting the provisions above and
031: * replace them with the notice and other provisions required by the LGPL.
032: * If you do not delete the provisions above, a recipient may use your version
033: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
034: *
035: * This library is free software; you can redistribute it and/or modify it
036: * under the terms of the MPL as stated above or under the terms of the GNU
037: * Library General Public License as published by the Free Software Foundation;
038: * either version 2 of the License, or any later version.
039: *
040: * This library is distributed in the hope that it will be useful, but WITHOUT
041: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
042: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
043: * details.
044: *
045: * If you didn't download this code from the following link, you should check if
046: * you aren't using an obsolete version:
047: * http://www.lowagie.com/iText/
048: */
049: package com.lowagie.text.pdf;
050:
051: import java.io.IOException;
052: import java.io.OutputStream;
053: import java.util.ArrayList;
054: import java.util.HashMap;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Map;
058: import java.util.StringTokenizer;
059:
060: import com.lowagie.text.Document;
061: import com.lowagie.text.DocumentException;
062: import com.lowagie.text.ExceptionConverter;
063:
064: /**
065: *
066: * @author psoares
067: */
068: class PdfCopyFieldsImp extends PdfWriter {
069:
070: private static final PdfName iTextTag = new PdfName("_iTextTag_");
071: private static final Integer zero = new Integer(0);
072: ArrayList readers = new ArrayList();
073: HashMap readers2intrefs = new HashMap();
074: HashMap pages2intrefs = new HashMap();
075: HashMap visited = new HashMap();
076: ArrayList fields = new ArrayList();
077: RandomAccessFileOrArray file;
078: HashMap fieldTree = new HashMap();
079: ArrayList pageRefs = new ArrayList();
080: ArrayList pageDics = new ArrayList();
081: PdfDictionary resources = new PdfDictionary();
082: PdfDictionary form;
083: boolean closing = false;
084: Document nd;
085: private HashMap tabOrder;
086: private ArrayList calculationOrder = new ArrayList();
087: private ArrayList calculationOrderRefs;
088:
089: PdfCopyFieldsImp(OutputStream os) throws DocumentException {
090: this (os, '\0');
091: }
092:
093: PdfCopyFieldsImp(OutputStream os, char pdfVersion)
094: throws DocumentException {
095: super (new PdfDocument(), os);
096: pdf.addWriter(this );
097: if (pdfVersion != 0)
098: super .setPdfVersion(pdfVersion);
099: nd = new Document();
100: nd.addDocListener(pdf);
101: }
102:
103: void addDocument(PdfReader reader, List pagesToKeep)
104: throws DocumentException {
105: if (!readers2intrefs.containsKey(reader) && reader.isTampered())
106: throw new DocumentException("The document was reused.");
107: reader = new PdfReader(reader);
108: reader.selectPages(pagesToKeep);
109: if (reader.getNumberOfPages() == 0)
110: return;
111: reader.setTampered(false);
112: addDocument(reader);
113: }
114:
115: void addDocument(PdfReader reader) throws DocumentException {
116: if (!reader.isOpenedWithFullPermissions())
117: throw new IllegalArgumentException(
118: "PdfReader not opened with owner password");
119: openDoc();
120: if (readers2intrefs.containsKey(reader)) {
121: reader = new PdfReader(reader);
122: } else {
123: if (reader.isTampered())
124: throw new DocumentException("The document was reused.");
125: reader.consolidateNamedDestinations();
126: reader.setTampered(true);
127: }
128: reader.shuffleSubsetNames();
129: readers2intrefs.put(reader, new IntHashtable());
130: readers.add(reader);
131: int len = reader.getNumberOfPages();
132: IntHashtable refs = new IntHashtable();
133: for (int p = 1; p <= len; ++p) {
134: refs.put(reader.getPageOrigRef(p).getNumber(), 1);
135: reader.releasePage(p);
136: }
137: pages2intrefs.put(reader, refs);
138: visited.put(reader, new IntHashtable());
139: fields.add(reader.getAcroFields());
140: updateCalculationOrder(reader);
141: }
142:
143: private static String getCOName(PdfReader reader,
144: PRIndirectReference ref) {
145: String name = "";
146: while (ref != null) {
147: PdfObject obj = PdfReader.getPdfObject(ref);
148: if (obj == null || obj.type() != PdfObject.DICTIONARY)
149: break;
150: PdfDictionary dic = (PdfDictionary) obj;
151: PdfString t = (PdfString) PdfReader.getPdfObject(dic
152: .get(PdfName.T));
153: if (t != null) {
154: name = t.toUnicodeString() + "." + name;
155: }
156: ref = (PRIndirectReference) dic.get(PdfName.PARENT);
157: }
158: if (name.endsWith("."))
159: name = name.substring(0, name.length() - 1);
160: return name;
161: }
162:
163: private void updateCalculationOrder(PdfReader reader) {
164: PdfDictionary catalog = reader.getCatalog();
165: PdfDictionary acro = (PdfDictionary) PdfReader
166: .getPdfObject(catalog.get(PdfName.ACROFORM));
167: if (acro == null)
168: return;
169: PdfArray co = (PdfArray) PdfReader.getPdfObject(acro
170: .get(PdfName.CO));
171: if (co == null || co.size() == 0)
172: return;
173: AcroFields af = reader.getAcroFields();
174: ArrayList coa = co.getArrayList();
175: for (int k = 0; k < coa.size(); ++k) {
176: PdfObject obj = (PdfObject) coa.get(k);
177: if (obj == null || !obj.isIndirect())
178: continue;
179: String name = getCOName(reader, (PRIndirectReference) obj);
180: if (af.getFieldItem(name) == null)
181: continue;
182: name = "." + name;
183: if (calculationOrder.contains(name))
184: continue;
185: calculationOrder.add(name);
186: }
187: }
188:
189: void propagate(PdfObject obj, PdfIndirectReference refo,
190: boolean restricted) throws IOException {
191: if (obj == null)
192: return;
193: // if (refo != null)
194: // addToBody(obj, refo);
195: if (obj instanceof PdfIndirectReference)
196: return;
197: switch (obj.type()) {
198: case PdfObject.DICTIONARY:
199: case PdfObject.STREAM: {
200: PdfDictionary dic = (PdfDictionary) obj;
201: for (Iterator it = dic.getKeys().iterator(); it.hasNext();) {
202: PdfName key = (PdfName) it.next();
203: if (restricted
204: && (key.equals(PdfName.PARENT) || key
205: .equals(PdfName.KIDS)))
206: continue;
207: PdfObject ob = dic.get(key);
208: if (ob != null && ob.isIndirect()) {
209: PRIndirectReference ind = (PRIndirectReference) ob;
210: if (!setVisited(ind) && !isPage(ind)) {
211: PdfIndirectReference ref = getNewReference(ind);
212: propagate(PdfReader.getPdfObjectRelease(ind),
213: ref, restricted);
214: }
215: } else
216: propagate(ob, null, restricted);
217: }
218: break;
219: }
220: case PdfObject.ARRAY: {
221: ArrayList list = ((PdfArray) obj).getArrayList();
222: //PdfArray arr = new PdfArray();
223: for (Iterator it = list.iterator(); it.hasNext();) {
224: PdfObject ob = (PdfObject) it.next();
225: if (ob != null && ob.isIndirect()) {
226: PRIndirectReference ind = (PRIndirectReference) ob;
227: if (!isVisited(ind) && !isPage(ind)) {
228: PdfIndirectReference ref = getNewReference(ind);
229: propagate(PdfReader.getPdfObjectRelease(ind),
230: ref, restricted);
231: }
232: } else
233: propagate(ob, null, restricted);
234: }
235: break;
236: }
237: case PdfObject.INDIRECT: {
238: throw new RuntimeException(
239: "Reference pointing to reference.");
240: }
241: }
242: }
243:
244: private void adjustTabOrder(PdfArray annots,
245: PdfIndirectReference ind, PdfNumber nn) {
246: int v = nn.intValue();
247: ArrayList t = (ArrayList) tabOrder.get(annots);
248: if (t == null) {
249: t = new ArrayList();
250: int size = annots.size() - 1;
251: for (int k = 0; k < size; ++k) {
252: t.add(zero);
253: }
254: t.add(new Integer(v));
255: tabOrder.put(annots, t);
256: annots.add(ind);
257: } else {
258: int size = t.size() - 1;
259: for (int k = size; k >= 0; --k) {
260: if (((Integer) t.get(k)).intValue() <= v) {
261: t.add(k + 1, new Integer(v));
262: annots.getArrayList().add(k + 1, ind);
263: size = -2;
264: break;
265: }
266: }
267: if (size != -2) {
268: t.add(0, new Integer(v));
269: annots.getArrayList().add(0, ind);
270: }
271: }
272: }
273:
274: protected PdfArray branchForm(HashMap level,
275: PdfIndirectReference parent, String fname)
276: throws IOException {
277: PdfArray arr = new PdfArray();
278: for (Iterator it = level.entrySet().iterator(); it.hasNext();) {
279: Map.Entry entry = (Map.Entry) it.next();
280: String name = (String) entry.getKey();
281: Object obj = entry.getValue();
282: PdfIndirectReference ind = getPdfIndirectReference();
283: PdfDictionary dic = new PdfDictionary();
284: if (parent != null)
285: dic.put(PdfName.PARENT, parent);
286: dic.put(PdfName.T, new PdfString(name,
287: PdfObject.TEXT_UNICODE));
288: String fname2 = fname + "." + name;
289: int coidx = calculationOrder.indexOf(fname2);
290: if (coidx >= 0)
291: calculationOrderRefs.set(coidx, ind);
292: if (obj instanceof HashMap) {
293: dic.put(PdfName.KIDS, branchForm((HashMap) obj, ind,
294: fname2));
295: arr.add(ind);
296: addToBody(dic, ind);
297: } else {
298: ArrayList list = (ArrayList) obj;
299: dic.mergeDifferent((PdfDictionary) list.get(0));
300: if (list.size() == 3) {
301: dic.mergeDifferent((PdfDictionary) list.get(2));
302: int page = ((Integer) list.get(1)).intValue();
303: PdfDictionary pageDic = (PdfDictionary) pageDics
304: .get(page - 1);
305: PdfArray annots = (PdfArray) PdfReader
306: .getPdfObject(pageDic.get(PdfName.ANNOTS));
307: if (annots == null) {
308: annots = new PdfArray();
309: pageDic.put(PdfName.ANNOTS, annots);
310: }
311: PdfNumber nn = (PdfNumber) dic.get(iTextTag);
312: dic.remove(iTextTag);
313: adjustTabOrder(annots, ind, nn);
314: } else {
315: PdfArray kids = new PdfArray();
316: for (int k = 1; k < list.size(); k += 2) {
317: int page = ((Integer) list.get(k)).intValue();
318: PdfDictionary pageDic = (PdfDictionary) pageDics
319: .get(page - 1);
320: PdfArray annots = (PdfArray) PdfReader
321: .getPdfObject(pageDic
322: .get(PdfName.ANNOTS));
323: if (annots == null) {
324: annots = new PdfArray();
325: pageDic.put(PdfName.ANNOTS, annots);
326: }
327: PdfDictionary widget = new PdfDictionary();
328: widget.merge((PdfDictionary) list.get(k + 1));
329: widget.put(PdfName.PARENT, ind);
330: PdfNumber nn = (PdfNumber) widget.get(iTextTag);
331: widget.remove(iTextTag);
332: PdfIndirectReference wref = addToBody(widget)
333: .getIndirectReference();
334: adjustTabOrder(annots, wref, nn);
335: kids.add(wref);
336: propagate(widget, null, false);
337: }
338: dic.put(PdfName.KIDS, kids);
339: }
340: arr.add(ind);
341: addToBody(dic, ind);
342: propagate(dic, null, false);
343: }
344: }
345: return arr;
346: }
347:
348: protected void createAcroForms() throws IOException {
349: if (fieldTree.isEmpty())
350: return;
351: form = new PdfDictionary();
352: form.put(PdfName.DR, resources);
353: propagate(resources, null, false);
354: form.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g "));
355: tabOrder = new HashMap();
356: calculationOrderRefs = new ArrayList(calculationOrder);
357: form.put(PdfName.FIELDS, branchForm(fieldTree, null, ""));
358: PdfArray co = new PdfArray();
359: for (int k = 0; k < calculationOrderRefs.size(); ++k) {
360: Object obj = calculationOrderRefs.get(k);
361: if (obj instanceof PdfIndirectReference)
362: co.add((PdfIndirectReference) obj);
363: }
364: if (co.size() > 0)
365: form.put(PdfName.CO, co);
366: }
367:
368: public void close() {
369: if (closing) {
370: super .close();
371: return;
372: }
373: closing = true;
374: try {
375: closeIt();
376: } catch (Exception e) {
377: throw new ExceptionConverter(e);
378: }
379: }
380:
381: protected void closeIt() throws IOException {
382: for (int k = 0; k < readers.size(); ++k) {
383: ((PdfReader) readers.get(k)).removeFields();
384: }
385: for (int r = 0; r < readers.size(); ++r) {
386: PdfReader reader = (PdfReader) readers.get(r);
387: for (int page = 1; page <= reader.getNumberOfPages(); ++page) {
388: pageRefs.add(getNewReference(reader
389: .getPageOrigRef(page)));
390: pageDics.add(reader.getPageN(page));
391: }
392: }
393: mergeFields();
394: createAcroForms();
395: for (int r = 0; r < readers.size(); ++r) {
396: PdfReader reader = (PdfReader) readers.get(r);
397: for (int page = 1; page <= reader.getNumberOfPages(); ++page) {
398: PdfDictionary dic = reader.getPageN(page);
399: PdfIndirectReference pageRef = getNewReference(reader
400: .getPageOrigRef(page));
401: PdfIndirectReference parent = root.addPageRef(pageRef);
402: dic.put(PdfName.PARENT, parent);
403: propagate(dic, pageRef, false);
404: }
405: }
406: for (Iterator it = readers2intrefs.entrySet().iterator(); it
407: .hasNext();) {
408: Map.Entry entry = (Map.Entry) it.next();
409: PdfReader reader = (PdfReader) entry.getKey();
410: try {
411: file = reader.getSafeFile();
412: file.reOpen();
413: IntHashtable t = (IntHashtable) entry.getValue();
414: int keys[] = t.toOrderedKeys();
415: for (int k = 0; k < keys.length; ++k) {
416: PRIndirectReference ref = new PRIndirectReference(
417: reader, keys[k]);
418: addToBody(PdfReader.getPdfObjectRelease(ref), t
419: .get(keys[k]));
420: }
421: } finally {
422: try {
423: file.close();
424: reader.close();
425: } catch (Exception e) {
426: // empty on purpose
427: }
428: }
429: }
430: pdf.close();
431: }
432:
433: void addPageOffsetToField(HashMap fd, int pageOffset) {
434: if (pageOffset == 0)
435: return;
436: for (Iterator it = fd.values().iterator(); it.hasNext();) {
437: ArrayList page = ((AcroFields.Item) it.next()).page;
438: for (int k = 0; k < page.size(); ++k)
439: page.set(k, new Integer(((Integer) page.get(k))
440: .intValue()
441: + pageOffset));
442: }
443: }
444:
445: void createWidgets(ArrayList list, AcroFields.Item item) {
446: for (int k = 0; k < item.merged.size(); ++k) {
447: list.add(item.page.get(k));
448: PdfDictionary merged = (PdfDictionary) item.merged.get(k);
449: PdfObject dr = merged.get(PdfName.DR);
450: if (dr != null)
451: PdfFormField.mergeResources(resources,
452: (PdfDictionary) PdfReader.getPdfObject(dr));
453: PdfDictionary widget = new PdfDictionary();
454: for (Iterator it = merged.getKeys().iterator(); it
455: .hasNext();) {
456: PdfName key = (PdfName) it.next();
457: if (widgetKeys.containsKey(key))
458: widget.put(key, merged.get(key));
459: }
460: widget.put(iTextTag, new PdfNumber(((Integer) item.tabOrder
461: .get(k)).intValue() + 1));
462: list.add(widget);
463: }
464: }
465:
466: void mergeField(String name, AcroFields.Item item) {
467: HashMap map = fieldTree;
468: StringTokenizer tk = new StringTokenizer(name, ".");
469: if (!tk.hasMoreTokens())
470: return;
471: while (true) {
472: String s = tk.nextToken();
473: Object obj = map.get(s);
474: if (tk.hasMoreTokens()) {
475: if (obj == null) {
476: obj = new HashMap();
477: map.put(s, obj);
478: map = (HashMap) obj;
479: continue;
480: } else if (obj instanceof HashMap)
481: map = (HashMap) obj;
482: else
483: return;
484: } else {
485: if (obj instanceof HashMap)
486: return;
487: PdfDictionary merged = (PdfDictionary) item.merged
488: .get(0);
489: if (obj == null) {
490: PdfDictionary field = new PdfDictionary();
491: for (Iterator it = merged.getKeys().iterator(); it
492: .hasNext();) {
493: PdfName key = (PdfName) it.next();
494: if (fieldKeys.containsKey(key))
495: field.put(key, merged.get(key));
496: }
497: ArrayList list = new ArrayList();
498: list.add(field);
499: createWidgets(list, item);
500: map.put(s, list);
501: } else {
502: ArrayList list = (ArrayList) obj;
503: PdfDictionary field = (PdfDictionary) list.get(0);
504: PdfName type1 = (PdfName) field.get(PdfName.FT);
505: PdfName type2 = (PdfName) merged.get(PdfName.FT);
506: if (type1 == null || !type1.equals(type2))
507: return;
508: int flag1 = 0;
509: PdfObject f1 = field.get(PdfName.FF);
510: if (f1 != null && f1.isNumber())
511: flag1 = ((PdfNumber) f1).intValue();
512: int flag2 = 0;
513: PdfObject f2 = merged.get(PdfName.FF);
514: if (f2 != null && f2.isNumber())
515: flag2 = ((PdfNumber) f2).intValue();
516: if (type1.equals(PdfName.BTN)) {
517: if (((flag1 ^ flag2) & PdfFormField.FF_PUSHBUTTON) != 0)
518: return;
519: if ((flag1 & PdfFormField.FF_PUSHBUTTON) == 0
520: && ((flag1 ^ flag2) & PdfFormField.FF_RADIO) != 0)
521: return;
522: } else if (type1.equals(PdfName.CH)) {
523: if (((flag1 ^ flag2) & PdfFormField.FF_COMBO) != 0)
524: return;
525: }
526: createWidgets(list, item);
527: }
528: return;
529: }
530: }
531: }
532:
533: void mergeWithMaster(HashMap fd) {
534: for (Iterator it = fd.entrySet().iterator(); it.hasNext();) {
535: Map.Entry entry = (Map.Entry) it.next();
536: String name = (String) entry.getKey();
537: mergeField(name, (AcroFields.Item) entry.getValue());
538: }
539: }
540:
541: void mergeFields() {
542: int pageOffset = 0;
543: for (int k = 0; k < fields.size(); ++k) {
544: HashMap fd = ((AcroFields) fields.get(k)).getFields();
545: addPageOffsetToField(fd, pageOffset);
546: mergeWithMaster(fd);
547: pageOffset += ((PdfReader) readers.get(k))
548: .getNumberOfPages();
549: }
550: }
551:
552: public PdfIndirectReference getPageReference(int page) {
553: return (PdfIndirectReference) pageRefs.get(page - 1);
554: }
555:
556: protected PdfDictionary getCatalog(PdfIndirectReference rootObj) {
557: try {
558: PdfDictionary cat = pdf.getCatalog(rootObj);
559: if (form != null) {
560: PdfIndirectReference ref = addToBody(form)
561: .getIndirectReference();
562: cat.put(PdfName.ACROFORM, ref);
563: }
564: writeOutlines(cat, false);
565: return cat;
566: } catch (IOException e) {
567: throw new ExceptionConverter(e);
568: }
569: }
570:
571: protected PdfIndirectReference getNewReference(
572: PRIndirectReference ref) {
573: return new PdfIndirectReference(0, getNewObjectNumber(ref
574: .getReader(), ref.getNumber(), 0));
575: }
576:
577: protected int getNewObjectNumber(PdfReader reader, int number,
578: int generation) {
579: IntHashtable refs = (IntHashtable) readers2intrefs.get(reader);
580: int n = refs.get(number);
581: if (n == 0) {
582: n = getIndirectReferenceNumber();
583: refs.put(number, n);
584: }
585: return n;
586: }
587:
588: protected boolean isVisited(PdfReader reader, int number,
589: int generation) {
590: IntHashtable refs = (IntHashtable) readers2intrefs.get(reader);
591: return refs.containsKey(number);
592: }
593:
594: protected boolean isVisited(PRIndirectReference ref) {
595: IntHashtable refs = (IntHashtable) visited.get(ref.getReader());
596: return refs.containsKey(ref.getNumber());
597: }
598:
599: protected boolean setVisited(PRIndirectReference ref) {
600: IntHashtable refs = (IntHashtable) visited.get(ref.getReader());
601: return (refs.put(ref.getNumber(), 1) != 0);
602: }
603:
604: protected boolean isPage(PRIndirectReference ref) {
605: IntHashtable refs = (IntHashtable) pages2intrefs.get(ref
606: .getReader());
607: return refs.containsKey(ref.getNumber());
608: }
609:
610: RandomAccessFileOrArray getReaderFile(PdfReader reader) {
611: return file;
612: }
613:
614: public void openDoc() {
615: if (!nd.isOpen())
616: nd.open();
617: }
618:
619: protected static final HashMap widgetKeys = new HashMap();
620: protected static final HashMap fieldKeys = new HashMap();
621: static {
622: Integer one = new Integer(1);
623: widgetKeys.put(PdfName.SUBTYPE, one);
624: widgetKeys.put(PdfName.CONTENTS, one);
625: widgetKeys.put(PdfName.RECT, one);
626: widgetKeys.put(PdfName.NM, one);
627: widgetKeys.put(PdfName.M, one);
628: widgetKeys.put(PdfName.F, one);
629: widgetKeys.put(PdfName.BS, one);
630: widgetKeys.put(PdfName.BORDER, one);
631: widgetKeys.put(PdfName.AP, one);
632: widgetKeys.put(PdfName.AS, one);
633: widgetKeys.put(PdfName.C, one);
634: widgetKeys.put(PdfName.A, one);
635: widgetKeys.put(PdfName.STRUCTPARENT, one);
636: widgetKeys.put(PdfName.OC, one);
637: widgetKeys.put(PdfName.H, one);
638: widgetKeys.put(PdfName.MK, one);
639: widgetKeys.put(PdfName.DA, one);
640: widgetKeys.put(PdfName.Q, one);
641: fieldKeys.put(PdfName.AA, one);
642: fieldKeys.put(PdfName.FT, one);
643: fieldKeys.put(PdfName.TU, one);
644: fieldKeys.put(PdfName.TM, one);
645: fieldKeys.put(PdfName.FF, one);
646: fieldKeys.put(PdfName.V, one);
647: fieldKeys.put(PdfName.DV, one);
648: fieldKeys.put(PdfName.DS, one);
649: fieldKeys.put(PdfName.RV, one);
650: fieldKeys.put(PdfName.OPT, one);
651: fieldKeys.put(PdfName.MAXLEN, one);
652: fieldKeys.put(PdfName.TI, one);
653: fieldKeys.put(PdfName.I, one);
654: fieldKeys.put(PdfName.LOCK, one);
655: fieldKeys.put(PdfName.SV, one);
656: }
657: }
|