Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle more gracefully an input without name attribute + select without option child #151 #413

Merged
merged 1 commit into from
Nov 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) throws UnsupportedEncod

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