1 47 package com.lowagie.text.pdf; 48 49 import java.awt.Color ; 50 import java.io.IOException ; 51 import java.io.InputStream ; 52 import java.util.ArrayList ; 53 import java.util.Collections ; 54 import java.util.Comparator ; 55 import java.util.HashMap ; 56 import java.util.Iterator ; 57 import java.util.Map ; 58 59 import org.w3c.dom.Node ; 60 61 import com.lowagie.text.DocumentException; 62 import com.lowagie.text.Element; 63 import com.lowagie.text.ExceptionConverter; 64 import com.lowagie.text.Rectangle; 65 66 70 public class AcroFields { 71 72 PdfReader reader; 73 PdfWriter writer; 74 HashMap fields; 75 private int topFirst; 76 private HashMap sigNames; 77 private boolean append; 78 public static final int DA_FONT = 0; 79 public static final int DA_SIZE = 1; 80 public static final int DA_COLOR = 2; 81 private HashMap extensionFonts = new HashMap (); 82 private XfaForm xfa; 83 86 public static final int FIELD_TYPE_NONE = 0; 87 90 public static final int FIELD_TYPE_PUSHBUTTON = 1; 91 94 public static final int FIELD_TYPE_CHECKBOX = 2; 95 98 public static final int FIELD_TYPE_RADIOBUTTON = 3; 99 102 public static final int FIELD_TYPE_TEXT = 4; 103 106 public static final int FIELD_TYPE_LIST = 5; 107 110 public static final int FIELD_TYPE_COMBO = 6; 111 114 public static final int FIELD_TYPE_SIGNATURE = 7; 115 116 private boolean lastWasString; 117 118 119 private boolean generateAppearances = true; 120 121 private HashMap localFonts = new HashMap (); 122 123 private float extraMarginLeft; 124 private float extraMarginTop; 125 private ArrayList substitutionFonts; 126 127 AcroFields(PdfReader reader, PdfWriter writer) { 128 this.reader = reader; 129 this.writer = writer; 130 try { 131 xfa = new XfaForm(reader); 132 } 133 catch (Exception e) { 134 throw new ExceptionConverter(e); 135 } 136 if (writer instanceof PdfStamperImp) { 137 append = ((PdfStamperImp)writer).isAppend(); 138 } 139 fill(); 140 } 141 142 void fill() { 143 fields = new HashMap (); 144 PdfDictionary top = (PdfDictionary)PdfReader.getPdfObjectRelease(reader.getCatalog().get(PdfName.ACROFORM)); 145 if (top == null) 146 return; 147 PdfArray arrfds = (PdfArray)PdfReader.getPdfObjectRelease(top.get(PdfName.FIELDS)); 148 if (arrfds == null || arrfds.size() == 0) 149 return; 150 arrfds = null; 151 for (int k = 1; k <= reader.getNumberOfPages(); ++k) { 152 PdfDictionary page = reader.getPageNRelease(k); 153 PdfArray annots = (PdfArray)PdfReader.getPdfObjectRelease(page.get(PdfName.ANNOTS), page); 154 if (annots == null) 155 continue; 156 ArrayList arr = annots.getArrayList(); 157 for (int j = 0; j < arr.size(); ++j) { 158 PdfObject annoto = PdfReader.getPdfObject((PdfObject)arr.get(j), annots); 159 if (!(annoto instanceof PdfDictionary)) { 160 PdfReader.releaseLastXrefPartial((PdfObject)arr.get(j)); 161 continue; 162 } 163 PdfDictionary annot = (PdfDictionary)annoto; 164 if (!PdfName.WIDGET.equals(annot.get(PdfName.SUBTYPE))) { 165 PdfReader.releaseLastXrefPartial((PdfObject)arr.get(j)); 166 continue; 167 } 168 PdfDictionary widget = annot; 169 PdfDictionary dic = new PdfDictionary(); 170 dic.putAll(annot); 171 String name = ""; 172 PdfDictionary value = null; 173 PdfObject lastV = null; 174 while (annot != null) { 175 dic.mergeDifferent(annot); 176 PdfString t = (PdfString)PdfReader.getPdfObject(annot.get(PdfName.T)); 177 if (t != null) 178 name = t.toUnicodeString() + "." + name; 179 if (lastV == null && annot.get(PdfName.V) != null) 180 lastV = PdfReader.getPdfObjectRelease(annot.get(PdfName.V)); 181 if (value == null && t != null) { 182 value = annot; 183 if (annot.get(PdfName.V) == null && lastV != null) 184 value.put(PdfName.V, lastV); 185 } 186 annot = (PdfDictionary)PdfReader.getPdfObject(annot.get(PdfName.PARENT), annot); 187 } 188 if (name.length() > 0) 189 name = name.substring(0, name.length() - 1); 190 Item item = (Item)fields.get(name); 191 if (item == null) { 192 item = new Item(); 193 fields.put(name, item); 194 } 195 if (value == null) 196 item.values.add(widget); 197 else 198 item.values.add(value); 199 item.widgets.add(widget); 200 item.widget_refs.add(arr.get(j)); if (top != null) 202 dic.mergeDifferent(top); 203 item.merged.add(dic); 204 item.page.add(new Integer (k)); 205 item.tabOrder.add(new Integer (j)); 206 } 207 } 208 } 209 210 217 public String [] getAppearanceStates(String fieldName) { 218 Item fd = (Item)fields.get(fieldName); 219 if (fd == null) 220 return null; 221 HashMap names = new HashMap (); 222 PdfDictionary vals = (PdfDictionary)fd.values.get(0); 223 PdfObject opts = PdfReader.getPdfObject(vals.get(PdfName.OPT)); 224 if (opts != null) { 225 if (opts.isString()) 226 names.put(((PdfString)opts).toUnicodeString(), null); 227 else if (opts.isArray()) { 228 ArrayList list = ((PdfArray)opts).getArrayList(); 229 for (int k = 0; k < list.size(); ++k) { 230 PdfObject v = PdfReader.getPdfObject((PdfObject)list.get(k)); 231 if (v != null && v.isString()) 232 names.put(((PdfString)v).toUnicodeString(), null); 233 } 234 } 235 } 236 ArrayList wd = fd.widgets; 237 for (int k = 0; k < wd.size(); ++k) { 238 PdfDictionary dic = (PdfDictionary)wd.get(k); 239 dic = (PdfDictionary)PdfReader.getPdfObject(dic.get(PdfName.AP)); 240 if (dic == null) 241 continue; 242 PdfObject ob = PdfReader.getPdfObject(dic.get(PdfName.N)); 243 if (ob == null || !ob.isDictionary()) 244 continue; 245 dic = (PdfDictionary)ob; 246 for (Iterator it = dic.getKeys().iterator(); it.hasNext();) { 247 String name = PdfName.decodeName(((PdfName)it.next()).toString()); 248 names.put(name, null); 249 } 250 } 251 String out[] = new String [names.size()]; 252 return (String [])names.keySet().toArray(out); 253 } 254 255 private String [] getListOption(String fieldName, int idx) { 256 Item fd = getFieldItem(fieldName); 257 if (fd == null) 258 return null; 259 PdfObject obj = PdfReader.getPdfObject(((PdfDictionary)fd.merged.get(0)).get(PdfName.OPT)); 260 if (obj == null || !obj.isArray()) 261 return null; 262 PdfArray ar = (PdfArray)obj; 263 String [] ret = new String [ar.size()]; 264 ArrayList a = ar.getArrayList(); 265 for (int k = 0; k < a.size(); ++k) { 266 obj = PdfReader.getPdfObject((PdfObject)a.get(k)); 267 try { 268 if (obj.isArray()) { 269 obj = (PdfObject)((PdfArray)obj).getArrayList().get(idx); 270 } 271 if (obj.isString()) 272 ret[k] = ((PdfString)obj).toUnicodeString(); 273 else 274 ret[k] = obj.toString(); 275 } 276 catch (Exception e) { 277 ret[k] = ""; 278 } 279 } 280 return ret; 281 } 282 283 290 public String [] getListOptionExport(String fieldName) { 291 return getListOption(fieldName, 0); 292 } 293 294 301 public String [] getListOptionDisplay(String fieldName) { 302 return getListOption(fieldName, 1); 303 } 304 305 326 public boolean setListOption(String fieldName, String [] exportValues, String [] displayValues) { 327 if (exportValues == null && displayValues == null) 328 return false; 329 if (exportValues != null && displayValues != null && exportValues.length != displayValues.length) 330 throw new IllegalArgumentException ("The export and the display array must have the same size."); 331 int ftype = getFieldType(fieldName); 332 if (ftype != FIELD_TYPE_COMBO && ftype != FIELD_TYPE_LIST) 333 return false; 334 Item fd = (Item)fields.get(fieldName); 335 String [] sing = null; 336 if (exportValues == null && displayValues != null) 337 sing = displayValues; 338 else if (exportValues != null && displayValues == null) 339 sing = exportValues; 340 PdfArray opt = new PdfArray(); 341 if (sing != null) { 342 for (int k = 0; k < sing.length; ++k) 343 opt.add(new PdfString(sing[k], PdfObject.TEXT_UNICODE)); 344 } 345 else { 346 for (int k = 0; k < exportValues.length; ++k) { 347 PdfArray a = new PdfArray(); 348 a.add(new PdfString(exportValues[k], PdfObject.TEXT_UNICODE)); 349 a.add(new PdfString(displayValues[k], PdfObject.TEXT_UNICODE)); 350 opt.add(a); 351 } 352 } 353 ((PdfDictionary)fd.values.get(0)).put(PdfName.OPT, opt); 354 for (int j = 0; j < fd.merged.size(); ++j) 355 ((PdfDictionary)fd.merged.get(j)).put(PdfName.OPT, opt); 356 return true; 357 } 358 359 370 public int getFieldType(String fieldName) { 371 Item fd = getFieldItem(fieldName); 372 if (fd == null) 373 return FIELD_TYPE_NONE; 374 PdfObject type = PdfReader.getPdfObject(((PdfDictionary)fd.merged.get(0)).get(PdfName.FT)); 375 if (type == null) 376 return FIELD_TYPE_NONE; 377 int ff = 0; 378 PdfObject ffo = PdfReader.getPdfObject(((PdfDictionary)fd.merged.get(0)).get(PdfName.FF)); 379 if (ffo != null && ffo.type() == PdfObject.NUMBER) 380 ff = ((PdfNumber)ffo).intValue(); 381 if (PdfName.BTN.equals(type)) { 382 if ((ff & PdfFormField.FF_PUSHBUTTON) != 0) 383 return FIELD_TYPE_PUSHBUTTON; 384 if ((ff & PdfFormField.FF_RADIO) != 0) 385 return FIELD_TYPE_RADIOBUTTON; 386 else 387 return FIELD_TYPE_CHECKBOX; 388 } 389 else if (PdfName.TX.equals(type)) { 390 return FIELD_TYPE_TEXT; 391 } 392 else if (PdfName.CH.equals(type)) { 393 if ((ff & PdfFormField.FF_COMBO) != 0) 394 return FIELD_TYPE_COMBO; 395 else 396 return FIELD_TYPE_LIST; 397 } 398 else if (PdfName.SIG.equals(type)) { 399 return FIELD_TYPE_SIGNATURE; 400 } 401 return FIELD_TYPE_NONE; 402 } 403 404 408 public void exportAsFdf(FdfWriter writer) { 409 for (Iterator it = fields.entrySet().iterator(); it.hasNext();) { 410 Map.Entry entry = (Map.Entry )it.next(); 411 Item item = (Item)entry.getValue(); 412 String name = (String )entry.getKey(); 413 PdfObject v = PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.V)); 414 if (v == null) 415 continue; 416 String value = getField(name); 417 if (lastWasString) 418 writer.setFieldAsString(name, value); 419 else 420 writer.setFieldAsName(name, value); 421 } 422 } 423 424 432 public boolean renameField(String oldName, String newName) { 433 int idx1 = oldName.lastIndexOf('.') + 1; 434 int idx2 = newName.lastIndexOf('.') + 1; 435 if (idx1 != idx2) 436 return false; 437 if (!oldName.substring(0, idx1).equals(newName.substring(0, idx2))) 438 return false; 439 if (fields.containsKey(newName)) 440 return false; 441 Item item = (Item)fields.get(oldName); 442 if (item == null) 443 return false; 444 newName = newName.substring(idx2); 445 PdfString ss = new PdfString(newName, PdfObject.TEXT_UNICODE); 446 for (int k = 0; k < item.merged.size(); ++k) { 447 PdfDictionary dic = (PdfDictionary)item.values.get(k); 448 dic.put(PdfName.T, ss); 449 markUsed(dic); 450 dic = (PdfDictionary)item.merged.get(k); 451 dic.put(PdfName.T, ss); 452 } 453 fields.remove(oldName); 454 fields.put(newName, item); 455 return true; 456 } 457 458 public static Object [] splitDAelements(String da) { 459 try { 460 PRTokeniser tk = new PRTokeniser(PdfEncodings.convertToBytes(da, null)); 461 ArrayList stack = new ArrayList (); 462 Object ret[] = new Object [3]; 463 while (tk.nextToken()) { 464 if (tk.getTokenType() == PRTokeniser.TK_COMMENT) 465 continue; 466 if (tk.getTokenType() == PRTokeniser.TK_OTHER) { 467 String operator = tk.getStringValue(); 468 if (operator.equals("Tf")) { 469 if (stack.size() >= 2) { 470 ret[DA_FONT] = stack.get(stack.size() - 2); 471 ret[DA_SIZE] = new Float ((String )stack.get(stack.size() - 1)); 472 } 473 } 474 else if (operator.equals("g")) { 475 if (stack.size() >= 1) { 476 float gray = new Float ((String )stack.get(stack.size() - 1)).floatValue(); 477 if (gray != 0) 478 ret[DA_COLOR] = new GrayColor(gray); 479 } 480 } 481 else if (operator.equals("rg")) { 482 if (stack.size() >= 3) { 483 float red = new Float ((String )stack.get(stack.size() - 3)).floatValue(); 484 float green = new Float ((String )stack.get(stack.size() - 2)).floatValue(); 485 float blue = new Float ((String )stack.get(stack.size() - 1)).floatValue(); 486 ret[DA_COLOR] = new Color (red, green, blue); 487 } 488 } 489 else if (operator.equals("k")) { 490 if (stack.size() >= 4) { 491 float cyan = new Float ((String )stack.get(stack.size() - 4)).floatValue(); 492 float magenta = new Float ((String )stack.get(stack.size() - 3)).floatValue(); 493 float yellow = new Float ((String )stack.get(stack.size() - 2)).floatValue(); 494 float black = new Float ((String )stack.get(stack.size() - 1)).floatValue(); 495 ret[DA_COLOR] = new CMYKColor(cyan, magenta, yellow, black); 496 } 497 } 498 stack.clear(); 499 } 500 else 501 stack.add(tk.getStringValue()); 502 } 503 return ret; 504 } 505 catch (IOException ioe) { 506 throw new ExceptionConverter(ioe); 507 } 508 } 509 510 public void decodeGenericDictionary(PdfDictionary merged, BaseField tx) throws IOException , DocumentException { 511 int flags = 0; 512 PdfString da = (PdfString)PdfReader.getPdfObject(merged.get(PdfName.DA)); 514 if (da != null) { 515 Object dab[] = splitDAelements(da.toUnicodeString()); 516 if (dab[DA_SIZE] != null) 517 tx.setFontSize(((Float )dab[DA_SIZE]).floatValue()); 518 if (dab[DA_COLOR] != null) 519 tx.setTextColor((Color )dab[DA_COLOR]); 520 if (dab[DA_FONT] != null) { 521 PdfDictionary font = (PdfDictionary)PdfReader.getPdfObject(merged.get(PdfName.DR)); 522 if (font != null) { 523 font = (PdfDictionary)PdfReader.getPdfObject(font.get(PdfName.FONT)); 524 if (font != null) { 525 PdfObject po = font.get(new PdfName((String )dab[DA_FONT])); 526 if (po != null && po.type() == PdfObject.INDIRECT) { 527 PRIndirectReference por = (PRIndirectReference)po; 528 BaseFont bp = new DocumentFont((PRIndirectReference)po); 529 tx.setFont(bp); 530 Integer porkey = new Integer (por.getNumber()); 531 BaseFont porf = (BaseFont)extensionFonts.get(porkey); 532 if (porf == null) { 533 if (!extensionFonts.containsKey(porkey)) { 534 PdfDictionary fo = (PdfDictionary)PdfReader.getPdfObject(po); 535 PdfDictionary fd = (PdfDictionary)PdfReader.getPdfObject(fo.get(PdfName.FONTDESCRIPTOR)); 536 if (fd != null) { 537 PRStream prs = (PRStream)PdfReader.getPdfObject(fd.get(PdfName.FONTFILE2)); 538 if (prs == null) 539 prs = (PRStream)PdfReader.getPdfObject(fd.get(PdfName.FONTFILE3)); 540 if (prs == null) { 541 extensionFonts.put(porkey, null); 542 } 543 else { 544 try { 545 porf = BaseFont.createFont("font.ttf", BaseFont.IDENTITY_H, true, false, PdfReader.getStreamBytes(prs), null); 546 } 547 catch (Exception e) { 548 } 549 extensionFonts.put(porkey, porf); 550 } 551 } 552 } 553 } 554 if (tx instanceof TextField) 555 ((TextField)tx).setExtensionFont(porf); 556 } 557 else { 558 BaseFont bf = (BaseFont)localFonts.get(dab[DA_FONT]); 559 if (bf == null) { 560 String fn[] = (String [])stdFieldFontNames.get(dab[DA_FONT]); 561 if (fn != null) { 562 try { 563 String enc = "winansi"; 564 if (fn.length > 1) 565 enc = fn[1]; 566 bf = BaseFont.createFont(fn[0], enc, false); 567 tx.setFont(bf); 568 } 569 catch (Exception e) { 570 } 572 } 573 } 574 else 575 tx.setFont(bf); 576 } 577 } 578 } 579 } 580 } 581 PdfDictionary mk = (PdfDictionary)PdfReader.getPdfObject(merged.get(PdfName.MK)); 583 if (mk != null) { 584 PdfArray ar = (PdfArray)PdfReader.getPdfObject(mk.get(PdfName.BC)); 585 Color border = getMKColor(ar); 586 tx.setBorderColor(border); 587 if (border != null) 588 tx.setBorderWidth(1); 589 ar = (PdfArray)PdfReader.getPdfObject(mk.get(PdfName.BG)); 590 tx.setBackgroundColor(getMKColor(ar)); 591 PdfNumber rotation = (PdfNumber)PdfReader.getPdfObject(mk.get(PdfName.R)); 592 if (rotation != null) 593 tx.setRotation(rotation.intValue()); 594 } 595 PdfNumber nfl = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.F)); 597 flags = 0; 598 if (nfl != null) { 599 flags = nfl.intValue(); 600 if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) != 0) 601 tx.setVisibility(BaseField.HIDDEN); 602 else if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_NOVIEW) != 0) 603 tx.setVisibility(BaseField.HIDDEN_BUT_PRINTABLE); 604 else if ((flags & PdfFormField.FLAGS_PRINT) != 0) 605 tx.setVisibility(BaseField.VISIBLE); 606 else 607 tx.setVisibility(BaseField.VISIBLE_BUT_DOES_NOT_PRINT); 608 } 609 nfl = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.FF)); 611 flags = 0; 612 if (nfl != null) 613 flags = nfl.intValue(); 614 tx.setOptions(flags); 615 if ((flags & PdfFormField.FF_COMB) != 0) { 616 PdfNumber maxLen = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.MAXLEN)); 617 int len = 0; 618 if (maxLen != null) 619 len = maxLen.intValue(); 620 tx.setMaxCharacterLength(len); 621 } 622 nfl = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.Q)); 624 if (nfl != null) { 625 if (nfl.intValue() == PdfFormField.Q_CENTER) 626 tx.setAlignment(Element.ALIGN_CENTER); 627 else if (nfl.intValue() == PdfFormField.Q_RIGHT) 628 tx.setAlignment(Element.ALIGN_RIGHT); 629 } 630 PdfDictionary bs = (PdfDictionary)PdfReader.getPdfObject(merged.get(PdfName.BS)); 632 if (bs != null) { 633 PdfNumber w = (PdfNumber)PdfReader.getPdfObject(bs.get(PdfName.W)); 634 if (w != null) 635 tx.setBorderWidth(w.floatValue()); 636 PdfName s = (PdfName)PdfReader.getPdfObject(bs.get(PdfName.S)); 637 if (PdfName.D.equals(s)) 638 tx.setBorderStyle(PdfBorderDictionary.STYLE_DASHED); 639 else if (PdfName.B.equals(s)) 640 tx.setBorderStyle(PdfBorderDictionary.STYLE_BEVELED); 641 else if (PdfName.I.equals(s)) 642 tx.setBorderStyle(PdfBorderDictionary.STYLE_INSET); 643 else if (PdfName.U.equals(s)) 644 tx.setBorderStyle(PdfBorderDictionary.STYLE_UNDERLINE); 645 } 646 else { 647 PdfArray bd = (PdfArray)PdfReader.getPdfObject(merged.get(PdfName.BORDER)); 648 if (bd != null) { 649 ArrayList ar = bd.getArrayList(); 650 if (ar.size() >= 3) 651 tx.setBorderWidth(((PdfNumber)ar.get(2)).floatValue()); 652 if (ar.size() >= 4) 653 tx.setBorderStyle(PdfBorderDictionary.STYLE_DASHED); 654 } 655 } 656 } 657 658 PdfAppearance getAppearance(PdfDictionary merged, String text, String fieldName) throws IOException , DocumentException { 659 topFirst = 0; 660 TextField tx = null; 661 if (fieldCache == null || !fieldCache.containsKey(fieldName)) { 662 tx = new TextField(writer, null, null); 663 tx.setExtraMargin(extraMarginLeft, extraMarginTop); 664 tx.setBorderWidth(0); 665 tx.setSubstitutionFonts(substitutionFonts); 666 decodeGenericDictionary(merged, tx); 667 PdfArray rect = (PdfArray)PdfReader.getPdfObject(merged.get(PdfName.RECT)); 669 Rectangle box = PdfReader.getNormalizedRectangle(rect); 670 if (tx.getRotation() == 90 || tx.getRotation() == 270) 671 box = box.rotate(); 672 tx.setBox(box); 673 if (fieldCache != null) 674 fieldCache.put(fieldName, tx); 675 } 676 else { 677 tx = (TextField)fieldCache.get(fieldName); 678 tx.setWriter(writer); 679 } 680 PdfName fieldType = (PdfName)PdfReader.getPdfObject(merged.get(PdfName.FT)); 681 if (PdfName.TX.equals(fieldType)) { 682 tx.setText(text); 683 return tx.getAppearance(); 684 } 685 if (!PdfName.CH.equals(fieldType)) 686 throw new DocumentException("An appearance was requested without a variable text field."); 687 PdfArray opt = (PdfArray)PdfReader.getPdfObject(merged.get(PdfName.OPT)); 688 int flags = 0; 689 PdfNumber nfl = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.FF)); 690 if (nfl != null) 691 flags = nfl.intValue(); 692 if ((flags & PdfFormField.FF_COMBO) != 0 && opt == null) { 693 tx.setText(text); 694 return tx.getAppearance(); 695 } 696 if (opt != null) { 697 ArrayList op = opt.getArrayList(); 698 String choices[] = new String [op.size()]; 699 String choicesExp[] = new String [op.size()]; 700 for (int k = 0; k < op.size(); ++k) { 701 PdfObject obj = (PdfObject)op.get(k); 702 if (obj.isString()) { 703 choices[k] = choicesExp[k] = ((PdfString)obj).toUnicodeString(); 704 } 705 else { 706 ArrayList opar = ((PdfArray)obj).getArrayList(); 707 choicesExp[k] = ((PdfString)opar.get(0)).toUnicodeString(); 708 choices[k] = ((PdfString)opar.get(1)).toUnicodeString(); 709 } 710 } 711 if ((flags & PdfFormField.FF_COMBO) != 0) { 712 for (int k = 0; k < choices.length; ++k) { 713 if (text.equals(choicesExp[k])) { 714 text = choices[k]; 715 break; 716 } 717 } 718 tx.setText(text); 719 return tx.getAppearance(); 720 } 721 int idx = 0; 722 for (int k = 0; k < choicesExp.length; ++k) { 723 if (text.equals(choicesExp[k])) { 724 idx = k; 725 break; 726 } 727 } 728 tx.setChoices(choices); 729 tx.setChoiceExports(choicesExp); 730 tx.setChoiceSelection(idx); 731 } 732 PdfAppearance app = tx.getListAppearance(); 733 topFirst = tx.getTopFirst(); 734 return app; 735 } 736 737 Color getMKColor(PdfArray ar) { 738 if (ar == null) 739 return null; 740 ArrayList cc = ar.getArrayList(); 741 switch (cc.size()) { 742 case 1: 743 return new GrayColor(((PdfNumber)cc.get(0)).floatValue()); 744 case 3: 745 return new Color (ExtendedColor.normalize(((PdfNumber)cc.get(0)).floatValue()), ExtendedColor.normalize(((PdfNumber)cc.get(1)).floatValue()), ExtendedColor.normalize(((PdfNumber)cc.get(2)).floatValue())); 746 case 4: 747 return new CMYKColor(((PdfNumber)cc.get(0)).floatValue(), ((PdfNumber)cc.get(1)).floatValue(), ((PdfNumber)cc.get(2)).floatValue(), ((PdfNumber)cc.get(3)).floatValue()); 748 default: 749 return null; 750 } 751 } 752 753 757 public String getField(String name) { 758 if (xfa.isXfaPresent()) { 759 name = xfa.findFieldName(name, this); 760 if (name == null) 761 return null; 762 name = XfaForm.Xml2Som.getShortName(name); 763 return XfaForm.getNodeText(xfa.findDatasetsNode(name)); 764 } 765 Item item = (Item)fields.get(name); 766 if (item == null) 767 return null; 768 lastWasString = false; 769 PdfObject v = PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.V)); 770 if (v == null) 771 return ""; 772 PdfName type = (PdfName)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.FT)); 773 if (PdfName.BTN.equals(type)) { 774 PdfNumber ff = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.FF)); 775 int flags = 0; 776 if (ff != null) 777 flags = ff.intValue(); 778 if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) 779 return ""; 780 String value = ""; 781 if (v.isName()) 782 value = PdfName.decodeName(v.toString()); 783 else if (v.isString()) 784 value = ((PdfString)v).toUnicodeString(); 785 PdfObject opts = PdfReader.getPdfObject(((PdfDictionary)item.values.get(0)).get(PdfName.OPT)); 786 if (opts != null && opts.isArray()) { 787 ArrayList list = ((PdfArray)opts).getArrayList(); 788 int idx = 0; 789 try { 790 idx = Integer.parseInt(value); 791 PdfString ps = (PdfString)list.get(idx); 792 value = ps.toUnicodeString(); 793 lastWasString = true; 794 } 795 catch (Exception e) { 796 } 797 } 798 return value; 799 } 800 if (v.isString()) { 801 lastWasString = true; 802 return ((PdfString)v).toUnicodeString(); 803 } 804 return PdfName.decodeName(v.toString()); 805 } 806 807 826 public boolean setFieldProperty(String field, String name, Object value, int inst[]) { 827 if (writer == null) 828 throw new RuntimeException ("This AcroFields instance is read-only."); 829 try { 830 Item item = (Item)fields.get(field); 831 if (item == null) 832 return false; 833 InstHit hit = new InstHit(inst); 834 if (name.equalsIgnoreCase("textfont")) { 835 for (int k = 0; k < item.merged.size(); ++k) { 836 if (hit.isHit(k)) { 837 PdfString da = (PdfString)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(k)).get(PdfName.DA)); 838 PdfDictionary dr = (PdfDictionary)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(k)).get(PdfName.DR)); 839 if (da != null && dr != null) { 840 Object dao[] = splitDAelements(da.toUnicodeString()); 841 PdfAppearance cb = new PdfAppearance(); 842 if (dao[DA_FONT] != null) { 843 BaseFont bf = (BaseFont)value; 844 PdfName psn = (PdfName)PdfAppearance.stdFieldFontNames.get(bf.getPostscriptFontName()); 845 if (psn == null) { 846 psn = new PdfName(bf.getPostscriptFontName()); 847 } 848 PdfDictionary fonts = (PdfDictionary)PdfReader.getPdfObject(dr.get(PdfName.FONT)); 849 if (fonts == null) { 850 fonts = new PdfDictionary(); 851 dr.put(PdfName.FONT, fonts); 852 } 853 PdfIndirectReference fref = (PdfIndirectReference)fonts.get(psn); 854 PdfDictionary top = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.ACROFORM)); 855 markUsed(top); 856 dr = (PdfDictionary)PdfReader.getPdfObject(top.get(PdfName.DR)); 857 if (dr == null) { 858 dr = new PdfDictionary(); 859 top.put(PdfName.DR, dr); 860 } 861 markUsed(dr); 862 PdfDictionary fontsTop = (PdfDictionary)PdfReader.getPdfObject(dr.get(PdfName.FONT)); 863 if (fontsTop == null) { 864 fontsTop = new PdfDictionary(); 865 dr.put(PdfName.FONT, fontsTop); 866 } 867 markUsed(fontsTop); 868 PdfIndirectReference frefTop = (PdfIndirectReference)fontsTop.get(psn); 869 if (frefTop != null) { 870 if (fref == null) 871 fonts.put(psn, frefTop); 872 } 873 else if (fref == null) { 874 FontDetails fd; 875 if (bf.getFontType() == BaseFont.FONT_TYPE_DOCUMENT) { 876 fd = new FontDetails(null, ((DocumentFont)bf).getIndirectReference(), bf); 877 } 878 else { 879 bf.setSubset(false); 880 fd = writer.addSimple(bf); 881 localFonts.put(psn.toString().substring(1), bf); 882 } 883 fontsTop.put(psn, fd.getIndirectReference()); 884 fonts.put(psn, fd.getIndirectReference()); 885 } 886 ByteBuffer buf = cb.getInternalBuffer(); 887 buf.append(psn.getBytes()).append(' ').append(((Float )dao[DA_SIZE]).floatValue()).append(" Tf "); 888 if (dao[DA_COLOR] != null) 889 cb.setColorFill((Color )dao[DA_COLOR]); 890 PdfString s = new PdfString(cb.toString()); 891 ((PdfDictionary)item.merged.get(k)).put(PdfName.DA, s); 892 ((PdfDictionary)item.widgets.get(k)).put(PdfName.DA, s); 893 markUsed((PdfDictionary)item.widgets.get(k)); 894 } 895 } 896 } 897 } 898 } 899 else if (name.equalsIgnoreCase("textcolor")) { 900 for (int k = 0; k < item.merged.size(); ++k) { 901 if (hit.isHit(k)) { 902 PdfString da = (PdfString)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(k)).get(PdfName.DA)); 903 if (da != null) { 904 Object dao[] = splitDAelements(da.toUnicodeString()); 905 PdfAppearance cb = new PdfAppearance(); 906 if (dao[DA_FONT] != null) { 907 ByteBuffer buf = cb.getInternalBuffer(); 908 buf.append(new PdfName((String )dao[DA_FONT]).getBytes()).append(' ').append(((Float )dao[DA_SIZE]).floatValue()).append(" Tf "); 909 cb.setColorFill((Color )value); 910 PdfString s = new PdfString(cb.toString()); 911 ((PdfDictionary)item.merged.get(k)).put(PdfName.DA, s); 912 ((PdfDictionary)item.widgets.get(k)).put(PdfName.DA, s); 913 markUsed((PdfDictionary)item.widgets.get(k)); 914 } 915 } 916 } 917 } 918 } 919 else if (name.equalsIgnoreCase("textsize")) { 920 for (int k = 0; k < item.merged.size(); ++k) { 921 if (hit.isHit(k)) { 922 PdfString da = (PdfString)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(k)).get(PdfName.DA)); 923 if (da != null) { 924 Object dao[] = splitDAelements(da.toUnicodeString()); 925 PdfAppearance cb = new PdfAppearance(); 926 if (dao[DA_FONT] != null) { 927 ByteBuffer buf = cb.getInternalBuffer(); 928 buf.append(new PdfName((String )dao[DA_FONT]).getBytes()).append(' ').append(((Float )value).floatValue()).append(" Tf "); 929 if (dao[DA_COLOR] != null) 930 cb.setColorFill((Color )dao[DA_COLOR]); 931 PdfString s = new PdfString(cb.toString()); 932 ((PdfDictionary)item.merged.get(k)).put(PdfName.DA, s); 933 ((PdfDictionary)item.widgets.get(k)).put(PdfName.DA, s); 934 markUsed((PdfDictionary)item.widgets.get(k)); 935 } 936 } 937 } 938 } 939 } 940 else if (name.equalsIgnoreCase("bgcolor") || name.equalsIgnoreCase("bordercolor")) { 941 PdfName dname = (name.equalsIgnoreCase("bgcolor") ? PdfName.BG : PdfName.BC); 942 for (int k = 0; k < item.merged.size(); ++k) { 943 if (hit.isHit(k)) { 944 PdfObject obj = PdfReader.getPdfObject(((PdfDictionary)item.merged.get(k)).get(PdfName.MK)); 945 markUsed(obj); 946 PdfDictionary mk = (PdfDictionary)obj; 947 if (mk == null) { 948 if (value == null) 949 return true; 950 mk = new PdfDictionary(); 951 ((PdfDictionary)item.merged.get(k)).put(PdfName.MK, mk); 952 ((PdfDictionary)item.widgets.get(k)).put(PdfName.MK, mk); 953 markUsed((PdfDictionary)item.widgets.get(k)); 954 } 955 if (value == null) 956 mk.remove(dname); 957 else 958 mk.put(dname, PdfFormField.getMKColor((Color )value)); 959 } 960 } 961 } 962 else 963 return false; 964 return true; 965 } 966 catch (Exception e) { 967 throw new ExceptionConverter(e); 968 } 969 } 970 971 997 public boolean setFieldProperty(String field, String name, int value, int inst[]) { 998 if (writer == null) 999 throw new RuntimeException ("This AcroFields instance is read-only."); 1000 Item item = (Item)fields.get(field); 1001 if (item == null) 1002 return false; 1003 InstHit hit = new InstHit(inst); 1004 if (name.equalsIgnoreCase("flags")) { 1005 PdfNumber num = new PdfNumber(value); 1006 for (int k = 0; k < item.merged.size(); ++k) { 1007 if (hit.isHit(k)) { 1008 ((PdfDictionary)item.merged.get(k)).put(PdfName.F, num); 1009 ((PdfDictionary)item.widgets.get(k)).put(PdfName.F, num); 1010 markUsed((PdfDictionary)item.widgets.get(k)); 1011 } 1012 } 1013 } 1014 else if (name.equalsIgnoreCase("setflags")) { 1015 for (int k = 0; k < item.merged.size(); ++k) { 1016 if (hit.isHit(k)) { 1017 PdfNumber num = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.widgets.get(k)).get(PdfName.F)); 1018 int val = 0; 1019 if (num != null) 1020 val = num.intValue(); 1021 num = new PdfNumber(val | value); 1022 ((PdfDictionary)item.merged.get(k)).put(PdfName.F, num); 1023 ((PdfDictionary)item.widgets.get(k)).put(PdfName.F, num); 1024 markUsed((PdfDictionary)item.widgets.get(k)); 1025 } 1026 } 1027 } 1028 else if (name.equalsIgnoreCase("clrflags")) { 1029 for (int k = 0; k < item.merged.size(); ++k) { 1030 if (hit.isHit(k)) { 1031 PdfNumber num = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.widgets.get(k)).get(PdfName.F)); 1032 int val = 0; 1033 if (num != null) 1034 val = num.intValue(); 1035 num = new PdfNumber(val & (~value)); 1036 ((PdfDictionary)item.merged.get(k)).put(PdfName.F, num); 1037 ((PdfDictionary)item.widgets.get(k)).put(PdfName.F, num); 1038 markUsed((PdfDictionary)item.widgets.get(k)); 1039 } 1040 } 1041 } 1042 else if (name.equalsIgnoreCase("fflags")) { 1043 PdfNumber num = new PdfNumber(value); 1044 for (int k = 0; k < item.merged.size(); ++k) { 1045 if (hit.isHit(k)) { 1046 ((PdfDictionary)item.merged.get(k)).put(PdfName.FF, num); 1047 ((PdfDictionary)item.values.get(k)).put(PdfName.FF, num); 1048 markUsed((PdfDictionary)item.values.get(k)); 1049 } 1050 } 1051 } 1052 else if (name.equalsIgnoreCase("setfflags")) { 1053 for (int k = 0; k < item.merged.size(); ++k) { 1054 if (hit.isHit(k)) { 1055 PdfNumber num = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.values.get(k)).get(PdfName.FF)); 1056 int val = 0; 1057 if (num != null) 1058 val = num.intValue(); 1059 num = new PdfNumber(val | value); 1060 ((PdfDictionary)item.merged.get(k)).put(PdfName.FF, num); 1061 ((PdfDictionary)item.values.get(k)).put(PdfName.FF, num); 1062 markUsed((PdfDictionary)item.values.get(k)); 1063 } 1064 } 1065 } 1066 else if (name.equalsIgnoreCase("clrfflags")) { 1067 for (int k = 0; k < item.merged.size(); ++k) { 1068 if (hit.isHit(k)) { 1069 PdfNumber num = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.values.get(k)).get(PdfName.FF)); 1070 int val = 0; 1071 if (num != null) 1072 val = num.intValue(); 1073 num = new PdfNumber(val & (~value)); 1074 ((PdfDictionary)item.merged.get(k)).put(PdfName.FF, num); 1075 ((PdfDictionary)item.values.get(k)).put(PdfName.FF, num); 1076 markUsed((PdfDictionary)item.values.get(k)); 1077 } 1078 } 1079 } 1080 else 1081 return false; 1082 return true; 1083 } 1084 1085 1091 public void mergeXfaData(Node n) throws IOException , DocumentException { 1092 XfaForm.Xml2SomDatasets data = new XfaForm.Xml2SomDatasets(n); 1093 for (Iterator it = data.getOrder().iterator(); it.hasNext();) { 1094 String name = (String )it.next(); 1095 String text = XfaForm.getNodeText((Node )data.getName2Node().get(name)); 1096 setField(name, text); 1097 } 1098 } 1099 1100 1105 public void setFields(FdfReader fdf) throws IOException , DocumentException { 1106 HashMap fd = fdf.getFields(); 1107 for (Iterator i = fd.keySet().iterator(); i.hasNext();) { 1108 String f = (String )i.next(); 1109 String v = fdf.getFieldValue(f); 1110 if (v != null) 1111 setField(f, v); 1112 } 1113 } 1114 1115 1120 1121 public void setFields(XfdfReader xfdf) throws IOException , DocumentException { 1122 HashMap fd = xfdf.getFields(); 1123 for (Iterator i = fd.keySet().iterator(); i.hasNext();) { 1124 String f = (String )i.next(); 1125 String v = xfdf.getFieldValue(f); 1126 if (v != null) 1127 setField(f, v); 1128 } 1129 } 1130 1131 1144 public boolean regenerateField(String name) throws IOException , DocumentException { 1145 String value = getField(name); 1146 return setField(name, value, value); 1147 } 1148 1149 1157 public boolean setField(String name, String value) throws IOException , DocumentException { 1158 return setField(name, value, null); 1159 } 1160 1161 1174 public boolean setField(String name, String value, String display) throws IOException , DocumentException { 1175 if (writer == null) 1176 throw new DocumentException("This AcroFields instance is read-only."); 1177 if (xfa.isXfaPresent()) { 1178 name = xfa.findFieldName(name, this); 1179 if (name == null) 1180 return false; 1181 String shortName = XfaForm.Xml2Som.getShortName(name); 1182 Node xn = xfa.findDatasetsNode(shortName); 1183 if (xn == null) { 1184 xn = xfa.getDatasetsSom().insertNode(xfa.getDatasetsNode(), shortName); 1185 } 1186 xfa.setNodeText(xn, value); 1187 } 1188 Item item = (Item)fields.get(name); 1189 if (item == null) 1190 return false; 1191 PdfName type = (PdfName)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.FT)); 1192 if (PdfName.TX.equals(type)) { 1193 PdfNumber maxLen = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.MAXLEN)); 1194 int len = 0; 1195 if (maxLen != null) 1196 len = maxLen.intValue(); 1197 if (len > 0) 1198 value = value.substring(0, Math.min(len, value.length())); 1199 } 1200 if (display == null) 1201 display = value; 1202 if (PdfName.TX.equals(type) || PdfName.CH.equals(type)) { 1203 PdfString v = new PdfString(value, PdfObject.TEXT_UNICODE); 1204 for (int idx = 0; idx < item.values.size(); ++idx) { 1205 PdfDictionary valueDic = (PdfDictionary)item.values.get(idx); 1206 valueDic.put(PdfName.V, v); 1207 valueDic.remove(PdfName.I); 1208 markUsed(valueDic); 1209 PdfDictionary merged = (PdfDictionary)item.merged.get(idx); 1210 merged.remove(PdfName.I); 1211 merged.put(PdfName.V, v); 1212 PdfDictionary widget = (PdfDictionary)item.widgets.get(idx); 1213 if (generateAppearances) { 1214 PdfAppearance app = getAppearance(merged, display, name); 1215 if (PdfName.CH.equals(type)) { 1216 PdfNumber n = new PdfNumber(topFirst); 1217 widget.put(PdfName.TI, n); 1218 merged.put(PdfName.TI, n); 1219 } 1220 PdfDictionary appDic = (PdfDictionary)PdfReader.getPdfObject(widget.get(PdfName.AP)); 1221 if (appDic == null) { 1222 appDic = new PdfDictionary(); 1223 widget.put(PdfName.AP, appDic); 1224 merged.put(PdfName.AP, appDic); 1225 } 1226 appDic.put(PdfName.N, app.getIndirectReference()); 1227 writer.releaseTemplate(app); 1228 } 1229 else { 1230 widget.remove(PdfName.AP); 1231 merged.remove(PdfName.AP); 1232 } 1233 markUsed(widget); 1234 } 1235 return true; 1236 } 1237 else if (PdfName.BTN.equals(type)) { 1238 PdfNumber ff = (PdfNumber)PdfReader.getPdfObject(((PdfDictionary)item.merged.get(0)).get(PdfName.FF)); 1239 int flags = 0; 1240 if (ff != null) 1241 flags = ff.intValue(); 1242 if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) 1243 return true; 1244 PdfName v = new PdfName(value); 1245 if ((flags & PdfFormField.FF_RADIO) == 0) { 1246 for (int idx = 0; idx < item.values.size(); ++idx) { 1247 ((PdfDictionary)item.values.get(idx)).put(PdfName.V, v); 1248 markUsed((PdfDictionary)item.values.get(idx)); 1249 PdfDictionary merged = (PdfDictionary)item.merged.get(idx); 1250 merged.put(PdfName.V, v); 1251 merged.put(PdfName.AS, v); 1252 PdfDictionary widget = (PdfDictionary)item.widgets.get(idx); 1253 if (isInAP(widget, v)) 1254 widget.put(PdfName.AS, v); 1255 else 1256 widget.put(PdfName.AS, PdfName.Off); 1257 markUsed(widget); 1258 } 1259 } 1260 else { 1261 ArrayList lopt = new ArrayList (); 1262 PdfObject opts = PdfReader.getPdfObject(((PdfDictionary)item.values.get(0)).get(PdfName.OPT)); 1263 if (opts != null && opts.isArray()) { 1264 ArrayList list = ((PdfArray)opts).getArrayList(); 1265 for (int k = 0; k < list.size(); ++k) { 1266 PdfObject vv = PdfReader.getPdfObject((PdfObject)list.get(k)); 1267 if (vv != null && vv.isString()) 1268 lopt.add(((PdfString)vv).toUnicodeString()); 1269 else 1270 lopt.add(null); 1271 } 1272 } 1273 int vidx = lopt.indexOf(value); 1274 PdfName valt = null; 1275 PdfName vt; 1276 if (vidx >= 0) { 1277 vt = valt = new PdfName(String.valueOf(vidx)); 1278 } 1279 else 1280 vt = v; 1281 for (int idx = 0; idx < item.values.size(); ++idx) { 1282 PdfDictionary merged = (PdfDictionary)item.merged.get(idx); 1283 PdfDictionary widget = (PdfDictionary)item.widgets.get(idx); 1284 markUsed((PdfDictionary)item.values.get(idx)); 1285 if (valt != null) { 1286 PdfString ps = new PdfString(value, PdfObject.TEXT_UNICODE); 1287 ((PdfDictionary)item.values.get(idx)).put(PdfName.V, ps); 1288 merged.put(PdfName.V, ps); 1289 } 1290 else { 1291 ((PdfDictionary)item.values.get(idx)).put(PdfName.V, v); 1292 merged.put(PdfName.V, v); 1293 } 1294 markUsed(widget); 1295 if (isInAP(widget, vt)) { 1296 merged.put(PdfName.AS, vt); 1297 widget.put(PdfName.AS, vt); 1298 } 1299 else { 1300 merged.put(PdfName.AS, PdfName.Off); 1301 widget.put(PdfName.AS, PdfName.Off); 1302 } 1303 } 1304 } 1305 return true; 1306 } 1307 return false; 1308 } 1309 1310 boolean isInAP(PdfDictionary dic, PdfName check) { 1311 PdfDictionary appDic = (PdfDictionary)PdfReader.getPdfObject(dic.get(PdfName.AP)); 1312 if (appDic == null) 1313 return false; 1314 PdfDictionary NDic = (PdfDictionary)PdfReader.getPdfObject(appDic.get(PdfName.N)); 1315 return (NDic != null && NDic.get(check) != null); 1316 } 1317 1318 1322 public HashMap getFields() { 1323 return fields; 1324 } 1325 1326 1332 public Item getFieldItem(String name) { 1333 if (xfa.isXfaPresent()) { 1334 name = xfa.findFieldName(name, this); 1335 if (name == null) 1336 return null; 1337 } 1338 return (Item)fields.get(name); 1339 } 1340 1341 1346 public String getTranslatedFieldName(String name) { 1347 if (xfa.isXfaPresent()) { 1348 String namex = xfa.findFieldName(name, this); 1349 if (namex != null) 1350 name = namex; 1351 } 1352 return name; 1353 } 1354 1355 1362 public float[] getFieldPositions(String name) { 1363 Item item = getFieldItem(name); 1364 if (item == null) 1365 return null; 1366 float ret[] = new float[item.page.size() * 5]; 1367 int ptr = 0; 1368 for (int k = 0; k < item.page.size(); ++k) { 1369 try { 1370 PdfDictionary wd = (PdfDictionary)item.widgets.get(k); 1371 PdfArray rect = (PdfArray)wd.get(PdfName.RECT); 1372 if (rect == null) 1373 continue; 1374 Rectangle r = PdfReader.getNormalizedRectangle(rect); 1375 int page = ((Integer )item.page.get(k)).intValue(); 1376 int rotation = reader.getPageRotation(page); 1377 ret[ptr++] = page; 1378 if (rotation != 0) { 1379 Rectangle pageSize = reader.getPageSize(page); 1380 switch (rotation) { 1381 case 270: 1382 r = new Rectangle( 1383 pageSize.getTop() - r.getBottom(), 1384 r.getLeft(), 1385 pageSize.getTop() - r.getTop(), 1386 r.getRight()); 1387 break; 1388 case 180: 1389 r = new Rectangle( 1390 pageSize.getRight() - r.getLeft(), 1391 pageSize.getTop() - r.getBottom(), 1392 pageSize.getRight() - r.getRight(), 1393 pageSize.getTop() - r.getTop()); 1394 break; 1395 case 90: 1396 r = new Rectangle( 1397 r.getBottom(), 1398 pageSize.getRight() - r.getLeft(), 1399 r.getTop(), 1400 pageSize.getRight() - r.getRight()); 1401 break; 1402 } 1403 r.normalize(); 1404 } 1405 ret[ptr++] = r.getLeft(); 1406 ret[ptr++] = r.getBottom(); 1407 ret[ptr++] = r.getRight(); 1408 ret[ptr++] = r.getTop(); 1409 } 1410 catch (Exception e) { 1411 } 1413 } 1414 if (ptr < ret.length) { 1415 float ret2[] = new float[ptr]; 1416 System.arraycopy(ret, 0, ret2, 0, ptr); 1417 return ret2; 1418 } 1419 return ret; 1420 } 1421 1422 private int removeRefFromArray(PdfArray array, PdfObject refo) { 1423 ArrayList ar = array.getArrayList(); 1424 if (refo == null || !refo.isIndirect()) 1425 return ar.size(); 1426 PdfIndirectReference ref = (PdfIndirectReference)refo; 1427 for (int j = 0; j < ar.size(); ++j) { 1428 PdfObject obj = (PdfObject)ar.get(j); 1429 if (!obj.isIndirect()) 1430 continue; 1431 if (((PdfIndirectReference)obj).getNumber() == ref.getNumber()) 1432 ar.remove(j--); 1433 } 1434 return ar.size(); 1435 } 1436 1437 1442 public boolean removeFieldsFromPage(int page) { 1443 if (page < 1) 1444 return false; 1445 String names[] = new String [fields.size()]; 1446 fields.keySet().toArray(names); 1447 boolean found = false; 1448 for (int k = 0; k < names.length; ++k) { 1449 boolean fr = removeField(names[k], page); 1450 found = (found || fr); 1451 } 1452 return found; 1453 } 1454 1455 1463 public boolean removeField(String name, int page) { 1464 Item item = getFieldItem(name); 1465 if (item == null) 1466 return false; 1467 PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.ACROFORM), reader.getCatalog()); 1468 1469 if (acroForm == null) 1470 return false; 1471 PdfArray arrayf = (PdfArray)PdfReader.getPdfObject(acroForm.get(PdfName.FIELDS), acroForm); 1472 if (arrayf == null) 1473 return false; 1474 for (int k = 0; k < item.widget_refs.size(); ++k) { 1475 int pageV = ((Integer )item.page.get(k)).intValue(); 1476 if (page != -1 && page != pageV) 1477 continue; 1478 PdfIndirectReference ref = (PdfIndirectReference)item.widget_refs.get(k); 1479 PdfDictionary wd = (PdfDictionary)PdfReader.getPdfObject(ref); 1480 PdfDictionary pageDic = reader.getPageN(pageV); 1481 PdfArray annots = (PdfArray)PdfReader.getPdfObject(pageDic.get(PdfName.ANNOTS), pageDic); 1482 if (annots != null) { 1483 if (removeRefFromArray(annots, ref) == 0) { 1484 pageDic.remove(PdfName.ANNOTS); 1485 markUsed(pageDic); 1486 } 1487 else 1488 markUsed(annots); 1489 } 1490 PdfReader.killIndirect(ref); 1491 PdfIndirectReference kid = ref; 1492 while ((ref = (PdfIndirectReference)wd.get(PdfName.PARENT)) != null) { 1493 wd = (PdfDictionary)PdfReader.getPdfObject(ref); 1494 PdfArray kids = (PdfArray)PdfReader.getPdfObject(wd.get(PdfName.KIDS)); 1495 if (removeRefFromArray(kids, kid) != 0) 1496 break; 1497 kid = ref; 1498 PdfReader.killIndirect(ref); 1499 } 1500 if (ref == null) { 1501 removeRefFromArray(arrayf, kid); 1502 markUsed(arrayf); 1503 } 1504 if (page != -1) { 1505 item.merged.remove(k); 1506 item.page.remove(k); 1507 item.values.remove(k); 1508 item.widget_refs.remove(k); 1509 item.widgets.remove(k); 1510 --k; 1511 } 1512 } 1513 if (page == -1 || item.merged.size() == 0) 1514 fields.remove(name); 1515 return true; 1516 } 1517 1518 1523 public boolean removeField(String name) { 1524 return removeField(name, -1); 1525 } 1526 1527 1530 public boolean isGenerateAppearances() { 1531 return this.generateAppearances; 1532 } 1533 1534 1540 public void setGenerateAppearances(boolean generateAppearances) { 1541 this.generateAppearances = generateAppearances; 1542 PdfDictionary top = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.ACROFORM)); 1543 if (generateAppearances) 1544 top.remove(PdfName.NEEDAPPEARANCES); 1545 else 1546 top.put(PdfName.NEEDAPPEARANCES, PdfBoolean.PDFTRUE); 1547 } 1548 1549 1550 public static class Item { 1551 1554 public ArrayList values = new ArrayList (); 1555 1557 public ArrayList widgets = new ArrayList (); 1558 1560 public ArrayList widget_refs = new ArrayList (); 1561 1564 public ArrayList merged = new ArrayList (); 1565 1568 public ArrayList page = new ArrayList (); 1569 1571 public ArrayList tabOrder = new ArrayList (); 1572 } 1573 1574 private static class InstHit { 1575 IntHashtable hits; 1576 public InstHit(int inst[]) { 1577 if (inst == null) 1578 return; 1579 hits = new IntHashtable(); 1580 for (int k = 0; k < inst.length; ++k) 1581 hits.put(inst[k], 1); 1582 } 1583 1584 public boolean isHit(int n) { 1585 if (hits == null) 1586 return true; 1587 return hits.containsKey(n); 1588 } 1589 } 1590 1591 1595 public ArrayList getSignatureNames() { 1596 if (sigNames != null) 1597 return new ArrayList (sigNames.keySet()); 1598 sigNames = new HashMap (); 1599 ArrayList sorter = new ArrayList (); 1600 for (Iterator it = fields.entrySet().iterator(); it.hasNext();) { 1601 Map.Entry entry = (Map.Entry )it.next(); 1602 Item item = (Item)entry.getValue(); 1603 PdfDictionary merged = (PdfDictionary)item.merged.get(0); 1604 if (!PdfName.SIG.equals(merged.get(PdfName.FT))) 1605 continue; 1606 PdfObject vo = PdfReader.getPdfObject(merged.get(PdfName.V)); 1607 if (vo == null || vo.type() != PdfObject.DICTIONARY) 1608 continue; 1609 PdfDictionary v = (PdfDictionary)vo; 1610 PdfObject contents = v.get(PdfName.CONTENTS); 1611 if (contents == null || contents.type() != PdfObject.STRING) 1612 continue; 1613 PdfObject ro = v.get(PdfName.BYTERANGE); 1614 if (ro == null || ro.type() != PdfObject.ARRAY) 1615 continue; 1616 ArrayList ra = ((PdfArray)ro).getArrayList(); 1617 if (ra.size() < 2) 1618 continue; 1619 int length = ((PdfNumber)ra.get(ra.size() - 1)).intValue() + ((PdfNumber)ra.get(ra.size() - 2)).intValue(); 1620 sorter.add(new Object []{entry.getKey(), new int[]{length, 0}}); 1621 } 1622 Collections.sort(sorter, new AcroFields.SorterComparator()); 1623 if (!sorter.isEmpty()) { 1624 if (((int[])((Object [])sorter.get(sorter.size() - 1))[1])[0] == reader.getFileLength()) 1625 totalRevisions = sorter.size(); 1626 else 1627 totalRevisions = sorter.size() + 1; 1628 for (int k = 0; k < sorter.size(); ++k) { 1629 Object objs[] = (Object [])sorter.get(k); 1630 String name = (String )objs[0]; 1631 int p[] = (int[])objs[1]; 1632 p[1] = k + 1; 1633 sigNames.put(name, p); 1634 } 1635 } 1636 return new ArrayList (sigNames.keySet()); 1637 } 1638 1639 1643 public ArrayList getBlankSignatureNames() { 1644 getSignatureNames(); 1645 ArrayList sigs = new ArrayList (); 1646 for (Iterator it = fields.entrySet().iterator(); it.hasNext();) { 1647 Map.Entry entry = (Map.Entry )it.next(); 1648 Item item = (Item)entry.getValue(); 1649 PdfDictionary merged = (PdfDictionary)item.merged.get(0); 1650 if (!PdfName.SIG.equals(merged.get(PdfName.FT))) 1651 continue; 1652 if (sigNames.containsKey(entry.getKey())) 1653 continue; 1654 sigs.add(entry.getKey()); 1655 } 1656 return sigs; 1657 } 1658 1659 1665 public PdfDictionary getSignatureDictionary(String name) { 1666 getSignatureNames(); 1667 name = getTranslatedFieldName(name); 1668 if (!sigNames.containsKey(name)) 1669 return null; 1670 Item item = (Item)fields.get(name); 1671 PdfDictionary merged = (PdfDictionary)item.merged.get(0); 1672 return (PdfDictionary)PdfReader.getPdfObject(merged.get(PdfName.V)); 1673 } 1674 1675 1681 public boolean signatureCoversWholeDocument(String name) { 1682 getSignatureNames(); 1683 name = getTranslatedFieldName(name); 1684 if (!sigNames.containsKey(name)) 1685 return false; 1686 return ((int[])sigNames.get(name))[0] == reader.getFileLength(); 1687 } 1688 1689 1716 public PdfPKCS7 verifySignature(String name) { 1717 return verifySignature(name, null); 1718 } 1719 1720 1748 public PdfPKCS7 verifySignature(String name, String provider) { 1749 PdfDictionary v = getSignatureDictionary(name); 1750 if (v == null) 1751 return null; 1752 try { 1753 PdfName sub = (PdfName)PdfReader.getPdfObject(v.get(PdfName.SUBFILTER)); 1754 PdfString contents = (PdfString)PdfReader.getPdfObject(v.get(PdfName.CONTENTS)); 1755 PdfPKCS7 pk = null; 1756 if (sub.equals(PdfName.ADBE_X509_RSA_SHA1)) { 1757 PdfString cert = (PdfString)PdfReader.getPdfObject(v.get(PdfName.CERT)); 1758 pk = new PdfPKCS7(contents.getOriginalBytes(), cert.getBytes(), provider); 1759 } 1760 else 1761 pk = new PdfPKCS7(contents.getOriginalBytes(), provider); 1762 updateByteRange(pk, v); 1763 PdfString str = (PdfString)PdfReader.getPdfObject(v.get(PdfName.M)); 1764 if (str != null) 1765 pk.setSignDate(PdfDate.decode(str.toString())); 1766 PdfObject obj = PdfReader.getPdfObject(v.get(PdfName.NAME)); 1767 if (obj != null) { 1768 if (obj.isString()) 1769 pk.setSignName(((PdfString)obj).toUnicodeString()); 1770 else if(obj.isName()) 1771 pk.setSignName(PdfName.decodeName(obj.toString())); 1772 } 1773 str = (PdfString)PdfReader.getPdfObject(v.get(PdfName.REASON)); 1774 if (str != null) 1775 pk.setReason(str.toUnicodeString()); 1776 str = (PdfString)PdfReader.getPdfObject(v.get(PdfName.LOCATION)); 1777 if (str != null) 1778 pk.setLocation(str.toUnicodeString()); 1779 return pk; 1780 } 1781 catch (Exception e) { 1782 throw new ExceptionConverter(e); 1783 } 1784 } 1785 1786 private void updateByteRange(PdfPKCS7 pkcs7, PdfDictionary v) { 1787 PdfArray b = (PdfArray)PdfReader.getPdfObject(v.get(PdfName.BYTERANGE)); 1788 RandomAccessFileOrArray rf = reader.getSafeFile(); 1789 try { 1790 rf.reOpen(); 1791 byte buf[] = new byte[8192]; 1792 ArrayList ar = b.getArrayList(); 1793 for (int k = 0; k < ar.size(); ++k) { 1794 int start = ((PdfNumber)ar.get(k)).intValue(); 1795 int length = ((PdfNumber)ar.get(++k)).intValue(); 1796 rf.seek(start); 1797 while (length > 0) { 1798 int rd = rf.read(buf, 0, Math.min(length, buf.length)); 1799 if (rd <= 0) 1800 break; 1801 length -= rd; 1802 pkcs7.update(buf, 0, rd); 1803 } 1804 } 1805 } 1806 catch (Exception e) { 1807 throw new ExceptionConverter(e); 1808 } 1809 finally { 1810 try{rf.close();}catch(Exception e){} 1811 } 1812 } 1813 1814 private void markUsed(PdfObject obj) { 1815 if (!append) 1816 return; 1817 ((PdfStamperImp)writer).markUsed(obj); 1818 } 1819 1820 1824 public int getTotalRevisions() { 1825 getSignatureNames(); 1826 return this.totalRevisions; 1827 } 1828 1829 1834 public int getRevision(String field) { 1835 getSignatureNames(); 1836 field = getTranslatedFieldName(field); 1837 if (!sigNames.containsKey(field)) 1838 return 0; 1839 return ((int[])sigNames.get(field))[1]; 1840 } 1841 1842 1849 public InputStream extractRevision(String field) throws IOException { 1850 getSignatureNames(); 1851 field = getTranslatedFieldName(field); 1852 if (!sigNames.containsKey(field)) 1853 return null; 1854 int length = ((int[])sigNames.get(field))[0]; 1855 RandomAccessFileOrArray raf = reader.getSafeFile(); 1856 raf.reOpen(); 1857 raf.seek(0); 1858 return new RevisionStream(raf, length); 1859 } 1860 1861 1865 public HashMap getFieldCache() { 1866 return this.fieldCache; 1867 } 1868 1869 1893 public void setFieldCache(HashMap fieldCache) { 1894 this.fieldCache = fieldCache; 1895 } 1896 1897 1902 public void setExtraMargin(float extraMarginLeft, float extraMarginTop) { 1903 this.extraMarginLeft = extraMarginLeft; 1904 this.extraMarginTop = extraMarginTop; 1905 } 1906 1907 1912 public void addSubstitutionFont(BaseFont font) { 1913 if (substitutionFonts == null) 1914 substitutionFonts = new ArrayList (); 1915 substitutionFonts.add(font); 1916 } 1917 1918 private static final HashMap stdFieldFontNames = new HashMap (); 1919 1920 1923 private int totalRevisions; 1924 1925 1928 private HashMap fieldCache; 1929 1930 static { 1931 stdFieldFontNames.put("CoBO", new String []{"Courier-BoldOblique"}); 1932 stdFieldFontNames.put("CoBo", new String []{"Courier-Bold"}); 1933 stdFieldFontNames.put("CoOb", new String []{"Courier-Oblique"}); 1934 stdFieldFontNames.put("Cour", new String []{"Courier"}); 1935 stdFieldFontNames.put("HeBO", new String []{"Helvetica-BoldOblique"}); 1936 stdFieldFontNames.put("HeBo", new String []{"Helvetica-Bold"}); 1937 stdFieldFontNames.put("HeOb", new String []{"Helvetica-Oblique"}); 1938 stdFieldFontNames.put("Helv", new String []{"Helvetica"}); 1939 stdFieldFontNames.put("Symb", new String []{"Symbol"}); 1940 stdFieldFontNames.put("TiBI", new String []{"Times-BoldItalic"}); 1941 stdFieldFontNames.put("TiBo", new String []{"Times-Bold"}); 1942 stdFieldFontNames.put("TiIt", new String []{"Times-Italic"}); 1943 stdFieldFontNames.put("TiRo", new String []{"Times-Roman"}); 1944 stdFieldFontNames.put("ZaDb", new String []{"ZapfDingbats"}); 1945 stdFieldFontNames.put("HySm", new String []{"HYSMyeongJo-Medium", "UniKS-UCS2-H"}); 1946 stdFieldFontNames.put("HyGo", new String []{"HYGoThic-Medium", "UniKS-UCS2-H"}); 1947 stdFieldFontNames.put("KaGo", new String []{"HeiseiKakuGo-W5", "UniKS-UCS2-H"}); 1948 stdFieldFontNames.put("KaMi", new String []{"HeiseiMin-W3", "UniJIS-UCS2-H"}); 1949 stdFieldFontNames.put("MHei", new String []{"MHei-Medium", "UniCNS-UCS2-H"}); 1950 stdFieldFontNames.put("MSun", new String []{"MSung-Light", "UniCNS-UCS2-H"}); 1951 stdFieldFontNames.put("STSo", new String []{"STSong-Light", "UniGB-UCS2-H"}); 1952 } 1953 1954 private static class RevisionStream extends InputStream { 1955 private byte b[] = new byte[1]; 1956 private RandomAccessFileOrArray raf; 1957 private int length; 1958 private int rangePosition = 0; 1959 private boolean closed; 1960 1961 private RevisionStream(RandomAccessFileOrArray raf, int length) { 1962 this.raf = raf; 1963 this.length = length; 1964 } 1965 1966 public int read() throws IOException { 1967 int n = read(b); 1968 if (n != 1) 1969 return -1; 1970 return b[0] & 0xff; 1971 } 1972 1973 public int read(byte[] b, int off, int len) throws IOException { 1974 if (b == null) { 1975 throw new NullPointerException (); 1976 } else if ((off < 0) || (off > b.length) || (len < 0) || 1977 ((off + len) > b.length) || ((off + len) < 0)) { 1978 throw new IndexOutOfBoundsException (); 1979 } else if (len == 0) { 1980 return 0; 1981 } 1982 if (rangePosition >= length) { 1983 close(); 1984 return -1; 1985 } 1986 int elen = Math.min(len, length - rangePosition); 1987 raf.readFully(b, off, elen); 1988 rangePosition += elen; 1989 return elen; 1990 } 1991 1992 public void close() throws IOException { 1993 if (!closed) { 1994 raf.close(); 1995 closed = true; 1996 } 1997 } 1998 } 1999 2000 private static class SorterComparator implements Comparator { 2001 public int compare(Object o1, Object o2) { 2002 int n1 = ((int[])((Object [])o1)[1])[0]; 2003 int n2 = ((int[])((Object [])o2)[1])[0]; 2004 return n1 - n2; 2005 } 2006 } 2007 2008 2013 public ArrayList getSubstitutionFonts() { 2014 return substitutionFonts; 2015 } 2016 2017 2022 public void setSubstitutionFonts(ArrayList substitutionFonts) { 2023 this.substitutionFonts = substitutionFonts; 2024 } 2025 2026 2030 public XfaForm getXfa() { 2031 return xfa; 2032 } 2033 2034 private static final PdfName[] buttonRemove = {PdfName.MK, PdfName.F , PdfName.FF , PdfName.Q , PdfName.BS , PdfName.BORDER}; 2035 2036 2043 public PushbuttonField getNewPushbuttonFromField(String field) { 2044 try { 2045 if (getFieldType(field) != FIELD_TYPE_PUSHBUTTON) 2046 return null; 2047 float[] pos = getFieldPositions(field); 2048 Rectangle box = new Rectangle(pos[1], pos[2], pos[3], pos[4]); 2049 PushbuttonField newButton = new PushbuttonField(writer, box, null); 2050 Item item = getFieldItem(field); 2051 PdfDictionary dic = (PdfDictionary)item.merged.get(0); 2052 decodeGenericDictionary(dic, newButton); 2053 PdfDictionary mk = (PdfDictionary)PdfReader.getPdfObject(dic.get(PdfName.MK)); 2054 if (mk != null) { 2055 PdfString text = (PdfString)PdfReader.getPdfObject(mk.get(PdfName.CA)); 2056 if (text != null) 2057 newButton.setText(text.toUnicodeString()); 2058 PdfNumber tp = (PdfNumber)PdfReader.getPdfObject(mk.get(PdfName.TP)); 2059 if (tp != null) 2060 newButton.setLayout(tp.intValue() + 1); 2061 PdfDictionary ifit = (PdfDictionary)PdfReader.getPdfObject(mk.get(PdfName.IF)); 2062 if (ifit != null) { 2063 PdfName sw = (PdfName)PdfReader.getPdfObject(ifit.get(PdfName.SW)); 2064 if (sw != null) { 2065 int scale = PushbuttonField.SCALE_ICON_ALWAYS; 2066 if (sw.equals(PdfName.B)) 2067 scale = PushbuttonField.SCALE_ICON_IS_TOO_BIG; 2068 else if (sw.equals(PdfName.S)) 2069 scale = PushbuttonField.SCALE_ICON_IS_TOO_SMALL; 2070 else if (sw.equals(PdfName.N)) 2071 scale = PushbuttonField.SCALE_ICON_NEVER; 2072 newButton.setScaleIcon(scale); 2073 } 2074 sw = (PdfName)PdfReader.getPdfObject(ifit.get(PdfName.S)); 2075 if (sw != null) { 2076 if (sw.equals(PdfName.A)) 2077 newButton.setProportionalIcon(false); 2078 } 2079 PdfArray aj = (PdfArray)PdfReader.getPdfObject(ifit.get(PdfName.A)); 2080 if (aj != null && aj.size() == 2) { 2081 float left = ((PdfNumber)PdfReader.getPdfObject((PdfObject)aj.getArrayList().get(0))).floatValue(); 2082 float bottom = ((PdfNumber)PdfReader.getPdfObject((PdfObject)aj.getArrayList().get(1))).floatValue(); 2083 newButton.setIconHorizontalAdjustment(left); 2084 newButton.setIconVerticalAdjustment(bottom); 2085 } 2086 PdfObject fb = PdfReader.getPdfObject(ifit.get(PdfName.FB)); 2087 if (fb != null && fb.toString().equals("true")) 2088 newButton.setIconFitToBounds(true); 2089 } 2090 PdfObject i = mk.get(PdfName.I); 2091 if (i != null && i.isIndirect()) 2092 newButton.setIconReference((PRIndirectReference)i); 2093 } 2094 return newButton; 2095 } 2096 catch (Exception e) { 2097 throw new ExceptionConverter(e); 2098 } 2099 } 2100 2101 2110 public boolean replacePushbuttonField(String field, PdfFormField button) { 2111 if (getFieldType(field) != FIELD_TYPE_PUSHBUTTON) 2112 return false; 2113 Item item = getFieldItem(field); 2114 PdfDictionary merged = (PdfDictionary)item.merged.get(0); 2115 PdfDictionary values = (PdfDictionary)item.values.get(0); 2116 PdfDictionary widgets = (PdfDictionary)item.widgets.get(0); 2117 for (int k = 0; k < buttonRemove.length; ++k) { 2118 merged.remove(buttonRemove[k]); 2119 values.remove(buttonRemove[k]); 2120 widgets.remove(buttonRemove[k]); 2121 } 2122 for (Iterator it = button.getKeys().iterator(); it.hasNext();) { 2123 PdfName key = (PdfName)it.next(); 2124 if (key.equals(PdfName.T) || key.equals(PdfName.RECT)) 2125 continue; 2126 merged.put(key, button.get(key)); 2127 widgets.put(key, button.get(key)); 2128 } 2129 return true; 2130 } 2131} 2132 | Popular Tags |