/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.tom_roush.pdfbox.pdmodel.interactive.form; import com.tom_roush.pdfbox.cos.COSDictionary; import com.tom_roush.pdfbox.cos.COSName; /** * A PDField factory. */ final class PDFieldFactory { private PDFieldFactory() { } private static final String FIELD_TYPE_TEXT = "Tx"; private static final String FIELD_TYPE_BUTTON = "Btn"; private static final String FIELD_TYPE_CHOICE = "Ch"; private static final String FIELD_TYPE_SIGNATURE = "Sig"; /** * Creates a COSField subclass from the given field. * * @param form the form that the field is part of * @param field the dictionary representing a field element * @param parent the parent node of the node to be created * @return the corresponding PDField instance */ static PDField createField(PDAcroForm form, COSDictionary field, PDNonTerminalField parent) { String fieldType = findFieldType(field); if (FIELD_TYPE_CHOICE.equals(fieldType)) { return createChoiceSubType(form, field, parent); } else if (FIELD_TYPE_TEXT.equals(fieldType)) { return new PDTextField(form, field, parent); } else if (FIELD_TYPE_SIGNATURE.equals(fieldType)) { return new PDSignatureField(form, field, parent); } else if (FIELD_TYPE_BUTTON.equals(fieldType)) { return createButtonSubType(form, field, parent); } else if (field.containsKey(COSName.KIDS)) { return new PDNonTerminalField(form, field, parent); } else { // an erroneous non-field object, see PDFBOX-2885 return null; } } private static PDField createChoiceSubType(PDAcroForm form, COSDictionary field, PDNonTerminalField parent) { int flags = field.getInt(COSName.FF, 0); if ((flags & PDChoice.FLAG_COMBO) != 0) { return new PDComboBox(form, field, parent); } else { return new PDListBox(form, field, parent); } } private static PDField createButtonSubType(PDAcroForm form, COSDictionary field, PDNonTerminalField parent) { int flags = field.getInt(COSName.FF, 0); // BJL: I have found that the radio flag bit is not always set // and that sometimes there is just a kids dictionary. // so, if there is a kids dictionary then it must be a radio button group. if ((flags & PDButton.FLAG_RADIO) != 0) { return new PDRadioButton(form, field, parent); } else if ((flags & PDButton.FLAG_PUSHBUTTON) != 0) { return new PDPushButton(form, field, parent); } else { return new PDCheckbox(form, field, parent); } } private static String findFieldType(COSDictionary dic) { String retval = dic.getNameAsString(COSName.FT); if (retval == null) { COSDictionary parent = (COSDictionary) dic.getDictionaryObject(COSName.PARENT, COSName.P); if (parent != null) { retval = findFieldType(parent); } } return retval; } }