Skip to content

Commit

Permalink
Merge pull request #413 from syjer/151-npe-form-missing-name-attribute
Browse files Browse the repository at this point in the history
handle more gracefully an input without name attribute + select without option child fixes #151
  • Loading branch information
danfickle committed Nov 18, 2019
2 parents 45c8b51 + 72b50a4 commit 8a53d43
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>
<body>
<form>
<input type="text"/>
<input type="radio"/>
<textarea/>
<input type="checkbox"/>
<select/>
<input type="hidden"/>
</form>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,21 @@ public void testFormControlAfterOverflowPage() throws IOException {

remove("form-control-after-overflow-page", doc);
}

/**
* Check that an input without name attribute does not launch a NPE.
* Will now log a warning message.
* See issue: https://github.com/danfickle/openhtmltopdf/issues/151
*
* Additionally, check that a select element without options will not launch a NPE too.
*/
@Test
public void testInputWithoutNameAttribute() throws IOException {
PDDocument doc = run("input-without-name-attribute");
PDAcroForm form = doc.getDocumentCatalog().getAcroForm();
assertEquals(0, form.getFields().size());
remove("input-without-name-attribute", doc);
}

// TODO:
// + More form controls.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
import com.openhtmltopdf.util.ArrayUtil;
import com.openhtmltopdf.util.OpenUtil;
import com.openhtmltopdf.util.XRLog;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;


public class PdfBoxForm {
Expand Down Expand Up @@ -263,6 +265,10 @@ private String getTextareaText(Element e) {

private String populateOptions(Element e, List<String> labels, List<String> values, List<Integer> selectedIndices) {
List<Element> opts = DOMUtil.getChildren(e, "option");
if (opts == null) {
XRLog.general(Level.WARNING, "A <"+e.getTagName() + "> element does not have <option> children");
return "";
}
String selected = "";
int i = 0;

Expand Down Expand Up @@ -297,10 +303,8 @@ private String populateOptions(Element e, List<String> labels, List<String> valu
private void processMultiSelectControl(ControlFontPair pair, Control ctrl, PDAcroForm acro, int i, Box root) throws IOException {
PDListBox field = new PDListBox(acro);

Field fObj = allFieldMap.get(ctrl.box.getElement().getAttribute("name"));
fObj.field = field;

field.setPartialName(fObj.partialName);
setPartialNameToField(ctrl, field);

field.setMultiSelect(true);

List<String> labels = new ArrayList<String>();
Expand Down Expand Up @@ -346,11 +350,8 @@ private void processMultiSelectControl(ControlFontPair pair, Control ctrl, PDAcr
*/
private void processSelectControl(ControlFontPair pair, Control ctrl, PDAcroForm acro, int i, Box root) throws IOException {
PDComboBox field = new PDComboBox(acro);

Field fObj = allFieldMap.get(ctrl.box.getElement().getAttribute("name"));
fObj.field = field;

field.setPartialName(fObj.partialName);

setPartialNameToField(ctrl, field);

List<String> labels = new ArrayList<String>();
List<String> values = new ArrayList<String>();
Expand Down Expand Up @@ -397,11 +398,8 @@ private void processSelectControl(ControlFontPair pair, Control ctrl, PDAcroForm

private void processHiddenControl(ControlFontPair pair, Control ctrl, PDAcroForm acro, int i, Box root) throws IOException {
PDTextField field = new PDTextField(acro);

Field fObj = allFieldMap.get(ctrl.box.getElement().getAttribute("name"));
fObj.field = field;

field.setPartialName(fObj.partialName);

setPartialNameToField(ctrl, field);

String value = ctrl.box.getElement().getAttribute("value");

Expand All @@ -418,11 +416,8 @@ private void processHiddenControl(ControlFontPair pair, Control ctrl, PDAcroForm

private void processTextControl(ControlFontPair pair, Control ctrl, PDAcroForm acro, int i, Box root) throws IOException {
PDTextField field = new PDTextField(acro);

Field fObj = allFieldMap.get(ctrl.box.getElement().getAttribute("name"));
fObj.field = field;

field.setPartialName(fObj.partialName);

setPartialNameToField(ctrl, field);

FSColor color = ctrl.box.getStyle().getColor();
String colorOperator = getColorOperator(color);
Expand Down Expand Up @@ -575,12 +570,9 @@ private COSString getCOSStringUTF16Encoded(String value) {

private void processCheckboxControl(ControlFontPair pair, PDAcroForm acro, int i, Control ctrl, Box root) throws IOException {
PDCheckBox field = new PDCheckBox(acro);

Field fObj = allFieldMap.get(ctrl.box.getElement().getAttribute("name"));
fObj.field = field;

field.setPartialName(fObj.partialName);


setPartialNameToField(ctrl, field);

if (ctrl.box.getElement().hasAttribute("required")) {
field.setRequired(true);
}
Expand Down Expand Up @@ -640,11 +632,9 @@ private void processCheckboxControl(ControlFontPair pair, PDAcroForm acro, int i
private void processRadioButtonGroup(List<Control> group, PDAcroForm acro, int i, Box root) throws IOException {
String groupName = group.get(0).box.getElement().getAttribute("name");
PDRadioButton field = new PDRadioButton(acro);

Field fObj = allFieldMap.get(groupName);
fObj.field = field;

field.setPartialName(fObj.partialName);
setPartialNameToField(group.get(0).box.getElement(), fObj, field);

List<String> values = new ArrayList<String>(group.size());
for (Control ctrl : group) {
Expand Down Expand Up @@ -767,6 +757,28 @@ private void processSubmitControl(PDAcroForm acro, int i, Control ctrl, Box root
acro.getFields().add(btn);
ctrl.page.getAnnotations().add(widget);
}

private void setPartialNameToField(Control ctrl, PDField field) {
Element elem = ctrl.box.getElement();
Field fObj = allFieldMap.get(elem.getAttribute("name"));
setPartialNameToField(elem, fObj, field);
}

private static void setPartialNameToField(Element element, Field fObj, PDField field) {
if (fObj != null) {
fObj.field = field;
field.setPartialName(fObj.partialName);
} else {
StringBuilder sb = new StringBuilder();
NamedNodeMap attributes = element.getAttributes();
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Node item = attributes.item(i);
sb.append(' ').append(item.getNodeName()).append("=\"").append(item.getNodeValue()).append('"');
}
XRLog.general(Level.WARNING, "found a <" + element.getTagName() + sb.toString() +"> element without attribute name, the element will not work without this attribute");
}
}

public int process(PDAcroForm acro, int startId, Box root) throws IOException {
processControlNames();
Expand Down Expand Up @@ -806,7 +818,7 @@ public int process(PDAcroForm acro, int startId, Box root) throws IOException {
e.getAttribute("type").equals("hidden")) {

processHiddenControl(pair, ctrl, acro, i, root);
}else if (e.getNodeName().equals("input") &&
} else if (e.getNodeName().equals("input") &&
e.getAttribute("type").equals("radio")) {
// We have to do radio button groups in one hit so add them to a map of list keyed on name.
List<Control> radioGroup = radioGroups.get(e.getAttribute("name"));
Expand Down

0 comments on commit 8a53d43

Please sign in to comment.