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