1 /*
2  * $Id$
3  * Copyright 2004 by Paulo Soares.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version 1.1
6  * (the "License"); you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the License.
12  *
13  * The Original Code is 'iText, a free JAVA-PDF library'.
14  *
15  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
16  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
17  * All Rights Reserved.
18  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
19  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
20  *
21  * Contributor(s): all the names of the contributors are added in the source code
22  * where applicable.
23  *
24  * Alternatively, the contents of this file may be used under the terms of the
25  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
26  * provisions of LGPL are applicable instead of those above.  If you wish to
27  * allow use of your version of this file only under the terms of the LGPL
28  * License and not to allow others to use your version of this file under
29  * the MPL, indicate your decision by deleting the provisions above and
30  * replace them with the notice and other provisions required by the LGPL.
31  * If you do not delete the provisions above, a recipient may use your version
32  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
33  *
34  * This library is free software; you can redistribute it and/or modify it
35  * under the terms of the MPL as stated above or under the terms of the GNU
36  * Library General Public License as published by the Free Software Foundation;
37  * either version 2 of the License, or any later version.
38  *
39  * This library is distributed in the hope that it will be useful, but WITHOUT
40  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
42  * details.
43  *
44  * If you didn't download this code from the following link, you should check if
45  * you aren't using an obsolete version:
46  * http://www.lowagie.com/iText/
47  */
48 package com.lowagie.text.pdf;
49 
50 import java.io.IOException;
51 import java.io.OutputStream;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.StringTokenizer;
58 import com.lowagie.text.error_messages.MessageLocalization;
59 
60 import com.lowagie.text.Document;
61 import com.lowagie.text.DocumentException;
62 import com.lowagie.text.ExceptionConverter;
63 import com.lowagie.text.exceptions.BadPasswordException;
64 
65 /**
66  *
67  * @author  psoares
68  */
69 class PdfCopyFieldsImp extends PdfWriter {
70 
71     private static final PdfName iTextTag = new PdfName("_iTextTag_");
72     private static final Integer zero = new Integer(0);
73     ArrayList readers = new ArrayList();
74     HashMap readers2intrefs = new HashMap();
75     HashMap pages2intrefs = new HashMap();
76     HashMap visited = new HashMap();
77     ArrayList fields = new ArrayList();
78     RandomAccessFileOrArray file;
79     HashMap fieldTree = new HashMap();
80     ArrayList pageRefs = new ArrayList();
81     ArrayList pageDics = new ArrayList();
82     PdfDictionary resources = new PdfDictionary();
83     PdfDictionary form;
84     boolean closing = false;
85     Document nd;
86     private HashMap tabOrder;
87     private ArrayList calculationOrder = new ArrayList();
88     private ArrayList calculationOrderRefs;
89     private boolean hasSignature;
90 
PdfCopyFieldsImp(OutputStream os)91     PdfCopyFieldsImp(OutputStream os) throws DocumentException {
92         this(os, '\0');
93     }
94 
PdfCopyFieldsImp(OutputStream os, char pdfVersion)95     PdfCopyFieldsImp(OutputStream os, char pdfVersion) throws DocumentException {
96         super(new PdfDocument(), os);
97         pdf.addWriter(this);
98         if (pdfVersion != 0)
99             super.setPdfVersion(pdfVersion);
100         nd = new Document();
101         nd.addDocListener(pdf);
102     }
103 
addDocument(PdfReader reader, List pagesToKeep)104     void addDocument(PdfReader reader, List pagesToKeep) throws DocumentException, IOException {
105         if (!readers2intrefs.containsKey(reader) && reader.isTampered())
106             throw new DocumentException(MessageLocalization.getComposedMessage("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 
addDocument(PdfReader reader)115     void addDocument(PdfReader reader) throws DocumentException, IOException {
116         if (!reader.isOpenedWithFullPermissions())
117             throw new BadPasswordException(MessageLocalization.getComposedMessage("pdfreader.not.opened.with.owner.password"));
118         openDoc();
119         if (readers2intrefs.containsKey(reader)) {
120             reader = new PdfReader(reader);
121         }
122         else {
123             if (reader.isTampered())
124                 throw new DocumentException(MessageLocalization.getComposedMessage("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 
getCOName(PdfReader reader, PRIndirectReference ref)143     private static String getCOName(PdfReader reader, PRIndirectReference ref) {
144         String name = "";
145         while (ref != null) {
146             PdfObject obj = PdfReader.getPdfObject(ref);
147             if (obj == null || obj.type() != PdfObject.DICTIONARY)
148                 break;
149             PdfDictionary dic = (PdfDictionary)obj;
150             PdfString t = dic.getAsString(PdfName.T);
151             if (t != null) {
152                 name = t.toUnicodeString()+ "." + name;
153             }
154             ref = (PRIndirectReference)dic.get(PdfName.PARENT);
155         }
156         if (name.endsWith("."))
157             name = name.substring(0, name.length() - 1);
158         return name;
159     }
160 
161     /**
162      * @since	2.1.5; before 2.1.5 the method was private
163      */
updateCalculationOrder(PdfReader reader)164     protected void updateCalculationOrder(PdfReader reader) {
165         PdfDictionary catalog = reader.getCatalog();
166         PdfDictionary acro = catalog.getAsDict(PdfName.ACROFORM);
167         if (acro == null)
168             return;
169         PdfArray co = acro.getAsArray(PdfName.CO);
170         if (co == null || co.size() == 0)
171             return;
172         AcroFields af = reader.getAcroFields();
173         for (int k = 0; k < co.size(); ++k) {
174             PdfObject obj = co.getPdfObject(k);
175             if (obj == null || !obj.isIndirect())
176                 continue;
177             String name = getCOName(reader, (PRIndirectReference)obj);
178             if (af.getFieldItem(name) == null)
179                 continue;
180             name = "." + name;
181             if (calculationOrder.contains(name))
182                 continue;
183             calculationOrder.add(name);
184         }
185     }
186 
propagate(PdfObject obj, PdfIndirectReference refo, boolean restricted)187     void propagate(PdfObject obj, PdfIndirectReference refo, boolean restricted) throws IOException {
188         if (obj == null)
189             return;
190 //        if (refo != null)
191 //            addToBody(obj, refo);
192         if (obj instanceof PdfIndirectReference)
193             return;
194         switch (obj.type()) {
195             case PdfObject.DICTIONARY:
196             case PdfObject.STREAM: {
197                 PdfDictionary dic = (PdfDictionary)obj;
198                 for (Iterator it = dic.getKeys().iterator(); it.hasNext();) {
199                     PdfName key = (PdfName)it.next();
200                     if (restricted && (key.equals(PdfName.PARENT) || key.equals(PdfName.KIDS)))
201                         continue;
202                     PdfObject ob = dic.get(key);
203                     if (ob != null && ob.isIndirect()) {
204                         PRIndirectReference ind = (PRIndirectReference)ob;
205                         if (!setVisited(ind) && !isPage(ind)) {
206                             PdfIndirectReference ref = getNewReference(ind);
207                             propagate(PdfReader.getPdfObjectRelease(ind), ref, restricted);
208                         }
209                     }
210                     else
211                         propagate(ob, null, restricted);
212                 }
213                 break;
214             }
215             case PdfObject.ARRAY: {
216                 //PdfArray arr = new PdfArray();
217                 for (Iterator it = ((PdfArray)obj).listIterator(); it.hasNext();) {
218                     PdfObject ob = (PdfObject)it.next();
219                     if (ob != null && ob.isIndirect()) {
220                         PRIndirectReference ind = (PRIndirectReference)ob;
221                         if (!isVisited(ind) && !isPage(ind)) {
222                             PdfIndirectReference ref = getNewReference(ind);
223                             propagate(PdfReader.getPdfObjectRelease(ind), ref, restricted);
224                         }
225                     }
226                     else
227                         propagate(ob, null, restricted);
228                 }
229                 break;
230             }
231             case PdfObject.INDIRECT: {
232                 throw new RuntimeException(MessageLocalization.getComposedMessage("reference.pointing.to.reference"));
233             }
234         }
235     }
236 
adjustTabOrder(PdfArray annots, PdfIndirectReference ind, PdfNumber nn)237     private void adjustTabOrder(PdfArray annots, PdfIndirectReference ind, PdfNumber nn) {
238         int v = nn.intValue();
239         ArrayList t = (ArrayList)tabOrder.get(annots);
240         if (t == null) {
241             t = new ArrayList();
242             int size = annots.size() - 1;
243             for (int k = 0; k < size; ++k) {
244                 t.add(zero);
245             }
246             t.add(new Integer(v));
247             tabOrder.put(annots, t);
248             annots.add(ind);
249         }
250         else {
251             int size = t.size() - 1;
252             for (int k = size; k >= 0; --k) {
253                 if (((Integer)t.get(k)).intValue() <= v) {
254                     t.add(k + 1, new Integer(v));
255                     annots.add(k + 1, ind);
256                     size = -2;
257                     break;
258                 }
259             }
260             if (size != -2) {
261                 t.add(0, new Integer(v));
262                 annots.add(0, ind);
263             }
264         }
265     }
266 
branchForm(HashMap level, PdfIndirectReference parent, String fname)267     protected PdfArray branchForm(HashMap level, PdfIndirectReference parent, String fname) throws IOException {
268         PdfArray arr = new PdfArray();
269         for (Iterator it = level.entrySet().iterator(); it.hasNext();) {
270             Map.Entry entry = (Map.Entry) it.next();
271             String name = (String) entry.getKey();
272             Object obj = entry.getValue();
273             PdfIndirectReference ind = getPdfIndirectReference();
274             PdfDictionary dic = new PdfDictionary();
275             if (parent != null)
276                 dic.put(PdfName.PARENT, parent);
277             dic.put(PdfName.T, new PdfString(name, PdfObject.TEXT_UNICODE));
278             String fname2 = fname + "." + name;
279             int coidx = calculationOrder.indexOf(fname2);
280             if (coidx >= 0)
281                 calculationOrderRefs.set(coidx, ind);
282             if (obj instanceof HashMap) {
283                 dic.put(PdfName.KIDS, branchForm((HashMap)obj, ind, fname2));
284                 arr.add(ind);
285                 addToBody(dic, ind);
286             }
287             else {
288                 ArrayList list = (ArrayList)obj;
289                 dic.mergeDifferent((PdfDictionary)list.get(0));
290                 if (list.size() == 3) {
291                     dic.mergeDifferent((PdfDictionary)list.get(2));
292                     int page = ((Integer)list.get(1)).intValue();
293                     PdfDictionary pageDic = (PdfDictionary)pageDics.get(page - 1);
294                     PdfArray annots = pageDic.getAsArray(PdfName.ANNOTS);
295                     if (annots == null) {
296                         annots = new PdfArray();
297                         pageDic.put(PdfName.ANNOTS, annots);
298                     }
299                     PdfNumber nn = (PdfNumber)dic.get(iTextTag);
300                     dic.remove(iTextTag);
301                     adjustTabOrder(annots, ind, nn);
302                 }
303                 else {
304                     PdfArray kids = new PdfArray();
305                     for (int k = 1; k < list.size(); k += 2) {
306                         int page = ((Integer)list.get(k)).intValue();
307                         PdfDictionary pageDic = (PdfDictionary)pageDics.get(page - 1);
308                         PdfArray annots = pageDic.getAsArray(PdfName.ANNOTS);
309                         if (annots == null) {
310                             annots = new PdfArray();
311                             pageDic.put(PdfName.ANNOTS, annots);
312                         }
313                         PdfDictionary widget = new PdfDictionary();
314                         widget.merge((PdfDictionary)list.get(k + 1));
315                         widget.put(PdfName.PARENT, ind);
316                         PdfNumber nn = (PdfNumber)widget.get(iTextTag);
317                         widget.remove(iTextTag);
318                         PdfIndirectReference wref = addToBody(widget).getIndirectReference();
319                         adjustTabOrder(annots, wref, nn);
320                         kids.add(wref);
321                         propagate(widget, null, false);
322                     }
323                     dic.put(PdfName.KIDS, kids);
324                 }
325                 arr.add(ind);
326                 addToBody(dic, ind);
327                 propagate(dic, null, false);
328             }
329         }
330         return arr;
331     }
332 
createAcroForms()333     protected void createAcroForms() throws IOException {
334         if (fieldTree.isEmpty())
335             return;
336         form = new PdfDictionary();
337         form.put(PdfName.DR, resources);
338         propagate(resources, null, false);
339         form.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g "));
340         tabOrder = new HashMap();
341         calculationOrderRefs = new ArrayList(calculationOrder);
342         form.put(PdfName.FIELDS, branchForm(fieldTree, null, ""));
343         if (hasSignature)
344             form.put(PdfName.SIGFLAGS, new PdfNumber(3));
345         PdfArray co = new PdfArray();
346         for (int k = 0; k < calculationOrderRefs.size(); ++k) {
347             Object obj = calculationOrderRefs.get(k);
348             if (obj instanceof PdfIndirectReference)
349                 co.add((PdfIndirectReference)obj);
350         }
351         if (co.size() > 0)
352             form.put(PdfName.CO, co);
353     }
354 
close()355     public void close() {
356         if (closing) {
357             super.close();
358             return;
359         }
360         closing = true;
361         try {
362             closeIt();
363         }
364         catch (Exception e) {
365             throw new ExceptionConverter(e);
366         }
367     }
368 
369     /**
370      * Creates the new PDF by merging the fields and forms.
371      */
closeIt()372     protected void closeIt() throws IOException {
373         for (int k = 0; k < readers.size(); ++k) {
374             ((PdfReader)readers.get(k)).removeFields();
375         }
376         for (int r = 0; r < readers.size(); ++r) {
377             PdfReader reader = (PdfReader)readers.get(r);
378             for (int page = 1; page <= reader.getNumberOfPages(); ++page) {
379                 pageRefs.add(getNewReference(reader.getPageOrigRef(page)));
380                 pageDics.add(reader.getPageN(page));
381             }
382         }
383         mergeFields();
384         createAcroForms();
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                     PdfDictionary dic = reader.getPageN(page);
389                     PdfIndirectReference pageRef = getNewReference(reader.getPageOrigRef(page));
390                     PdfIndirectReference parent = root.addPageRef(pageRef);
391                     dic.put(PdfName.PARENT, parent);
392                     propagate(dic, pageRef, false);
393                 }
394         }
395         for (Iterator it = readers2intrefs.entrySet().iterator(); it.hasNext();) {
396             Map.Entry entry = (Map.Entry) it.next();
397             PdfReader reader = (PdfReader) entry.getKey();
398             try {
399                 file = reader.getSafeFile();
400                 file.reOpen();
401                 IntHashtable t = (IntHashtable) entry.getValue();
402                 int keys[] = t.toOrderedKeys();
403                 for (int k = 0; k < keys.length; ++k) {
404                     PRIndirectReference ref = new PRIndirectReference(reader, keys[k]);
405                     addToBody(PdfReader.getPdfObjectRelease(ref), t.get(keys[k]));
406                 }
407             }
408             finally {
409                 try {
410                     file.close();
411                     reader.close();
412                 }
413                 catch (Exception e) {
414                     // empty on purpose
415                 }
416             }
417         }
418         pdf.close();
419     }
420 
addPageOffsetToField(HashMap fd, int pageOffset)421     void addPageOffsetToField(HashMap fd, int pageOffset) {
422         if (pageOffset == 0)
423             return;
424         for (Iterator it = fd.values().iterator(); it.hasNext();) {
425             AcroFields.Item item = (AcroFields.Item)it.next();
426             for (int k = 0; k < item.size(); ++k) {
427                 int p = item.getPage(k).intValue();
428                 item.forcePage(k, p + pageOffset);
429             }
430         }
431     }
432 
createWidgets(ArrayList list, AcroFields.Item item)433     void createWidgets(ArrayList list, AcroFields.Item item) {
434         for (int k = 0; k < item.size(); ++k) {
435             list.add(item.getPage(k));
436             PdfDictionary merged = item.getMerged(k);
437             PdfObject dr = merged.get(PdfName.DR);
438             if (dr != null)
439                 PdfFormField.mergeResources(resources, (PdfDictionary)PdfReader.getPdfObject(dr));
440             PdfDictionary widget = new PdfDictionary();
441             for (Iterator it = merged.getKeys().iterator(); it.hasNext();) {
442                 PdfName key = (PdfName)it.next();
443                 if (widgetKeys.containsKey(key))
444                     widget.put(key, merged.get(key));
445             }
446             widget.put(iTextTag, new PdfNumber(item.getTabOrder(k).intValue() + 1));
447             list.add(widget);
448         }
449     }
450 
mergeField(String name, AcroFields.Item item)451     void mergeField(String name, AcroFields.Item item) {
452         HashMap map = fieldTree;
453         StringTokenizer tk = new StringTokenizer(name, ".");
454         if (!tk.hasMoreTokens())
455             return;
456         while (true) {
457             String s = tk.nextToken();
458             Object obj = map.get(s);
459             if (tk.hasMoreTokens()) {
460                 if (obj == null) {
461                     obj = new HashMap();
462                     map.put(s, obj);
463                     map = (HashMap)obj;
464                     continue;
465                 }
466                 else if (obj instanceof HashMap)
467                     map = (HashMap)obj;
468                 else
469                     return;
470             }
471             else {
472                 if (obj instanceof HashMap)
473                     return;
474                 PdfDictionary merged = item.getMerged(0);
475                 if (obj == null) {
476                     PdfDictionary field = new PdfDictionary();
477                     if (PdfName.SIG.equals(merged.get(PdfName.FT)))
478                         hasSignature = true;
479                     for (Iterator it = merged.getKeys().iterator(); it.hasNext();) {
480                         PdfName key = (PdfName)it.next();
481                         if (fieldKeys.containsKey(key))
482                             field.put(key, merged.get(key));
483                     }
484                     ArrayList list = new ArrayList();
485                     list.add(field);
486                     createWidgets(list, item);
487                     map.put(s, list);
488                 }
489                 else {
490                     ArrayList list = (ArrayList)obj;
491                     PdfDictionary field = (PdfDictionary)list.get(0);
492                     PdfName type1 = (PdfName)field.get(PdfName.FT);
493                     PdfName type2 = (PdfName)merged.get(PdfName.FT);
494                     if (type1 == null || !type1.equals(type2))
495                         return;
496                     int flag1 = 0;
497                     PdfObject f1 = field.get(PdfName.FF);
498                     if (f1 != null && f1.isNumber())
499                         flag1 = ((PdfNumber)f1).intValue();
500                     int flag2 = 0;
501                     PdfObject f2 = merged.get(PdfName.FF);
502                     if (f2 != null && f2.isNumber())
503                         flag2 = ((PdfNumber)f2).intValue();
504                     if (type1.equals(PdfName.BTN)) {
505                         if (((flag1 ^ flag2) & PdfFormField.FF_PUSHBUTTON) != 0)
506                             return;
507                         if ((flag1 & PdfFormField.FF_PUSHBUTTON) == 0 && ((flag1 ^ flag2) & PdfFormField.FF_RADIO) != 0)
508                             return;
509                     }
510                     else if (type1.equals(PdfName.CH)) {
511                         if (((flag1 ^ flag2) & PdfFormField.FF_COMBO) != 0)
512                             return;
513                     }
514                     createWidgets(list, item);
515                 }
516                 return;
517             }
518         }
519     }
520 
mergeWithMaster(HashMap fd)521     void mergeWithMaster(HashMap fd) {
522         for (Iterator it = fd.entrySet().iterator(); it.hasNext();) {
523             Map.Entry entry = (Map.Entry) it.next();
524             String name = (String) entry.getKey();
525             mergeField(name, (AcroFields.Item) entry.getValue());
526         }
527     }
528 
mergeFields()529     void mergeFields() {
530         int pageOffset = 0;
531         for (int k = 0; k < fields.size(); ++k) {
532             HashMap fd = ((AcroFields)fields.get(k)).getFields();
533             addPageOffsetToField(fd, pageOffset);
534             mergeWithMaster(fd);
535             pageOffset += ((PdfReader)readers.get(k)).getNumberOfPages();
536         }
537     }
538 
getPageReference(int page)539     public PdfIndirectReference getPageReference(int page) {
540         return (PdfIndirectReference)pageRefs.get(page - 1);
541     }
542 
getCatalog(PdfIndirectReference rootObj)543     protected PdfDictionary getCatalog(PdfIndirectReference rootObj) {
544         try {
545             PdfDictionary cat = pdf.getCatalog(rootObj);
546             if (form != null) {
547                 PdfIndirectReference ref = addToBody(form).getIndirectReference();
548                 cat.put(PdfName.ACROFORM, ref);
549             }
550             return cat;
551         }
552         catch (IOException e) {
553             throw new ExceptionConverter(e);
554         }
555     }
556 
getNewReference(PRIndirectReference ref)557     protected PdfIndirectReference getNewReference(PRIndirectReference ref) {
558         return new PdfIndirectReference(0, getNewObjectNumber(ref.getReader(), ref.getNumber(), 0));
559     }
560 
getNewObjectNumber(PdfReader reader, int number, int generation)561     protected int getNewObjectNumber(PdfReader reader, int number, int generation) {
562         IntHashtable refs = (IntHashtable)readers2intrefs.get(reader);
563         int n = refs.get(number);
564         if (n == 0) {
565             n = getIndirectReferenceNumber();
566             refs.put(number, n);
567         }
568         return n;
569     }
570 
571 
572     /**
573      * Sets a reference to "visited" in the copy process.
574      * @param	ref	the reference that needs to be set to "visited"
575      * @return	true if the reference was set to visited
576      */
setVisited(PRIndirectReference ref)577     protected boolean setVisited(PRIndirectReference ref) {
578         IntHashtable refs = (IntHashtable)visited.get(ref.getReader());
579         if (refs != null)
580         	return (refs.put(ref.getNumber(), 1) != 0);
581         else
582         	return false;
583     }
584 
585     /**
586      * Checks if a reference has already been "visited" in the copy process.
587      * @param	ref	the reference that needs to be checked
588      * @return	true if the reference was already visited
589      */
isVisited(PRIndirectReference ref)590     protected boolean isVisited(PRIndirectReference ref) {
591         IntHashtable refs = (IntHashtable)visited.get(ref.getReader());
592         if (refs != null)
593         	return refs.containsKey(ref.getNumber());
594         else
595         	return false;
596     }
597 
isVisited(PdfReader reader, int number, int generation)598     protected boolean isVisited(PdfReader reader, int number, int generation) {
599         IntHashtable refs = (IntHashtable)readers2intrefs.get(reader);
600         return refs.containsKey(number);
601     }
602 
603     /**
604      * Checks if a reference refers to a page object.
605      * @param	ref	the reference that needs to be checked
606      * @return	true is the reference refers to a page object.
607      */
isPage(PRIndirectReference ref)608     protected boolean isPage(PRIndirectReference ref) {
609         IntHashtable refs = (IntHashtable)pages2intrefs.get(ref.getReader());
610         if (refs != null)
611         	return refs.containsKey(ref.getNumber());
612         else
613         	return false;
614     }
615 
getReaderFile(PdfReader reader)616     RandomAccessFileOrArray getReaderFile(PdfReader reader) {
617             return file;
618     }
619 
openDoc()620     public void openDoc() {
621         if (!nd.isOpen())
622             nd.open();
623     }
624 
625     protected static final HashMap widgetKeys = new HashMap();
626     protected static final HashMap fieldKeys = new HashMap();
627     static {
628         Integer one = new Integer(1);
widgetKeys.put(PdfName.SUBTYPE, one)629         widgetKeys.put(PdfName.SUBTYPE, one);
widgetKeys.put(PdfName.CONTENTS, one)630         widgetKeys.put(PdfName.CONTENTS, one);
widgetKeys.put(PdfName.RECT, one)631         widgetKeys.put(PdfName.RECT, one);
widgetKeys.put(PdfName.NM, one)632         widgetKeys.put(PdfName.NM, one);
widgetKeys.put(PdfName.M, one)633         widgetKeys.put(PdfName.M, one);
widgetKeys.put(PdfName.F, one)634         widgetKeys.put(PdfName.F, one);
widgetKeys.put(PdfName.BS, one)635         widgetKeys.put(PdfName.BS, one);
widgetKeys.put(PdfName.BORDER, one)636         widgetKeys.put(PdfName.BORDER, one);
widgetKeys.put(PdfName.AP, one)637         widgetKeys.put(PdfName.AP, one);
widgetKeys.put(PdfName.AS, one)638         widgetKeys.put(PdfName.AS, one);
widgetKeys.put(PdfName.C, one)639         widgetKeys.put(PdfName.C, one);
widgetKeys.put(PdfName.A, one)640         widgetKeys.put(PdfName.A, one);
widgetKeys.put(PdfName.STRUCTPARENT, one)641         widgetKeys.put(PdfName.STRUCTPARENT, one);
widgetKeys.put(PdfName.OC, one)642         widgetKeys.put(PdfName.OC, one);
widgetKeys.put(PdfName.H, one)643         widgetKeys.put(PdfName.H, one);
widgetKeys.put(PdfName.MK, one)644         widgetKeys.put(PdfName.MK, one);
widgetKeys.put(PdfName.DA, one)645         widgetKeys.put(PdfName.DA, one);
widgetKeys.put(PdfName.Q, one)646         widgetKeys.put(PdfName.Q, one);
fieldKeys.put(PdfName.AA, one)647         fieldKeys.put(PdfName.AA, one);
fieldKeys.put(PdfName.FT, one)648         fieldKeys.put(PdfName.FT, one);
fieldKeys.put(PdfName.TU, one)649         fieldKeys.put(PdfName.TU, one);
fieldKeys.put(PdfName.TM, one)650         fieldKeys.put(PdfName.TM, one);
fieldKeys.put(PdfName.FF, one)651         fieldKeys.put(PdfName.FF, one);
fieldKeys.put(PdfName.V, one)652         fieldKeys.put(PdfName.V, one);
fieldKeys.put(PdfName.DV, one)653         fieldKeys.put(PdfName.DV, one);
fieldKeys.put(PdfName.DS, one)654         fieldKeys.put(PdfName.DS, one);
fieldKeys.put(PdfName.RV, one)655         fieldKeys.put(PdfName.RV, one);
fieldKeys.put(PdfName.OPT, one)656         fieldKeys.put(PdfName.OPT, one);
fieldKeys.put(PdfName.MAXLEN, one)657         fieldKeys.put(PdfName.MAXLEN, one);
fieldKeys.put(PdfName.TI, one)658         fieldKeys.put(PdfName.TI, one);
fieldKeys.put(PdfName.I, one)659         fieldKeys.put(PdfName.I, one);
fieldKeys.put(PdfName.LOCK, one)660         fieldKeys.put(PdfName.LOCK, one);
fieldKeys.put(PdfName.SV, one)661         fieldKeys.put(PdfName.SV, one);
662     }
663 }
664