summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc')
-rw-r--r--Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc675
1 files changed, 675 insertions, 0 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
new file mode 100644
index 00000000000..6928fa9c9a8
--- /dev/null
+++ b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
@@ -0,0 +1,675 @@
+//========================================================================
+//
+// XFAScanner.cc
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "GHash.h"
+#include "Object.h"
+#include "Error.h"
+#include "Zoox.h"
+#include "XFAScanner.h"
+
+//------------------------------------------------------------------------
+
+// fields have two names:
+//
+// name:
+// - nodes with bind=global set the index to 0 ("foo[0]") regardless
+// of the number of nodes with the same name
+// - nodes with bind=none are dropped from the name
+// - <area> nodes are dropped from the name
+// - used for field value lookup in <xfa:datasets>
+//
+// fullName:
+// - all named nodes are treated the same, regardless of bind=global
+// or bind=none
+// - <area> nodes are included in the name, but don't reset the
+// numbering (i.e., <area> nodes are "transparent" with respect to
+// node numbering)
+// - used for field value lookup in <form>
+// - used for matching with AcroForm names
+//
+// Both names use indexes on all nodes, even if there's only one node
+// with the name -- this isn't correct for XFA naming, but it matches
+// the AcroForm behavior.
+
+//------------------------------------------------------------------------
+
+XFAFieldLayoutInfo::XFAFieldLayoutInfo(XFAFieldLayoutHAlign hAlignA,
+ XFAFieldLayoutVAlign vAlignA) {
+ hAlign = hAlignA;
+ vAlign = vAlignA;
+}
+
+//------------------------------------------------------------------------
+
+XFAFieldPictureInfo::XFAFieldPictureInfo(XFAFieldPictureSubtype subtypeA,
+ GString *formatA) {
+ subtype = subtypeA;
+ format = formatA;
+}
+
+XFAFieldPictureInfo::~XFAFieldPictureInfo() {
+ delete format;
+}
+
+//------------------------------------------------------------------------
+
+XFAFieldBarcodeInfo::XFAFieldBarcodeInfo(GString *barcodeTypeA,
+ double wideNarrowRatioA,
+ double moduleWidthA,
+ double moduleHeightA,
+ int dataLengthA,
+ int errorCorrectionLevelA,
+ GString *textLocationA) {
+ barcodeType = barcodeTypeA;
+ wideNarrowRatio = wideNarrowRatioA;
+ moduleWidth = moduleWidthA;
+ moduleHeight = moduleHeightA;
+ dataLength = dataLengthA;
+ errorCorrectionLevel = errorCorrectionLevelA;
+ textLocation = textLocationA;
+}
+
+XFAFieldBarcodeInfo::~XFAFieldBarcodeInfo() {
+ delete barcodeType;
+ delete textLocation;
+}
+
+//------------------------------------------------------------------------
+
+XFAField::XFAField(GString *nameA, GString *fullNameA, GString *valueA,
+ XFAFieldLayoutInfo *layoutInfoA,
+ XFAFieldPictureInfo *pictureInfoA,
+ XFAFieldBarcodeInfo *barcodeInfoA)
+ : name(nameA)
+ , fullName(fullNameA)
+ , value(valueA)
+ , layoutInfo(layoutInfoA)
+ , pictureInfo(pictureInfoA)
+ , barcodeInfo(barcodeInfoA)
+{
+}
+
+XFAField::~XFAField() {
+ delete name;
+ delete fullName;
+ delete value;
+ delete layoutInfo;
+ delete pictureInfo;
+ delete barcodeInfo;
+}
+
+//------------------------------------------------------------------------
+
+XFAScanner *XFAScanner::load(Object *xfaObj) {
+ GString *xfaData = readXFAStreams(xfaObj);
+ if (!xfaData) {
+ return NULL;
+ }
+ ZxDoc *xml = ZxDoc::loadMem(xfaData->getCString(), xfaData->getLength());
+ delete xfaData;
+ if (!xml) {
+ error(errSyntaxError, -1, "Invalid XML in XFA form");
+ return NULL;
+ }
+
+ XFAScanner *scanner = new XFAScanner();
+
+ if (xml->getRoot()) {
+ GHash *formValues = scanner->scanFormValues(xml->getRoot());
+ ZxElement *dataElem = NULL;
+ ZxElement *datasets =
+ xml->getRoot()->findFirstChildElement("xfa:datasets");
+ if (datasets) {
+ dataElem = datasets->findFirstChildElement("xfa:data");
+ }
+ ZxElement *tmpl = xml->getRoot()->findFirstChildElement("template");
+ if (tmpl) {
+ scanner->scanNode(tmpl, NULL, NULL, NULL, NULL, NULL,
+ dataElem, formValues);
+ }
+ deleteGHash(formValues, GString);
+ }
+
+ delete xml;
+
+ return scanner;
+}
+
+XFAScanner::XFAScanner() {
+ fields = new GHash();
+}
+
+XFAScanner::~XFAScanner() {
+ deleteGHash(fields, XFAField);
+}
+
+XFAField *XFAScanner::findField(GString *acroFormFieldName) {
+ return (XFAField *)fields->lookup(acroFormFieldName);
+}
+
+GString *XFAScanner::readXFAStreams(Object *xfaObj) {
+ GString *data = new GString();
+ char buf[4096];
+ int n;
+ if (xfaObj->isStream()) {
+ xfaObj->streamReset();
+ while ((n = xfaObj->getStream()->getBlock(buf, sizeof(buf))) > 0) {
+ data->append(buf, n);
+ }
+ } else if (xfaObj->isArray()) {
+ for (int i = 1; i < xfaObj->arrayGetLength(); i += 2) {
+ Object obj;
+ if (!xfaObj->arrayGet(i, &obj)->isStream()) {
+ error(errSyntaxError, -1, "XFA array element is wrong type");
+ obj.free();
+ delete data;
+ return NULL;
+ }
+ obj.streamReset();
+ while ((n = obj.getStream()->getBlock(buf, sizeof(buf))) > 0) {
+ data->append(buf, n);
+ }
+ obj.free();
+ }
+ } else {
+ error(errSyntaxError, -1, "XFA object is wrong type");
+ return NULL;
+ }
+ return data;
+}
+
+GHash *XFAScanner::scanFormValues(ZxElement *xmlRoot) {
+ GHash *formValues = new GHash(gTrue);
+ ZxElement *formElem = xmlRoot->findFirstChildElement("form");
+ if (formElem) {
+ scanFormNode(formElem, NULL, formValues);
+ }
+ return formValues;
+}
+
+void XFAScanner::scanFormNode(ZxElement *elem, GString *fullName,
+ GHash *formValues) {
+ GHash *fullNameIdx = new GHash();
+ for (ZxNode *node = elem->getFirstChild();
+ node;
+ node = node->getNextChild()) {
+ if (node->isElement("value")) {
+ if (fullName) {
+ ZxNode *child1Node = ((ZxElement *)node)->getFirstChild();
+ if (child1Node && child1Node->isElement()) {
+ ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
+ if (child2Node && child2Node->isCharData()) {
+ formValues->add(fullName->copy(),
+ ((ZxCharData *)child2Node)->getData()->copy());
+ }
+ }
+ }
+ } else if (node->isElement()) {
+ ZxAttr *nameAttr = ((ZxElement *)node)->findAttr("name");
+ if (nameAttr && (node->isElement("subform") ||
+ node->isElement("field"))) {
+ GString *nodeName = nameAttr->getValue();
+ GString *childFullName;
+ if (fullName) {
+ childFullName = GString::format("{0:t}.{1:t}", fullName, nodeName);
+ } else {
+ childFullName = nodeName->copy();
+ }
+ int idx = fullNameIdx->lookupInt(nodeName);
+ childFullName->appendf("[{0:d}]", idx);
+ fullNameIdx->replace(nodeName, idx + 1);
+ scanFormNode((ZxElement *)node, childFullName, formValues);
+ delete childFullName;
+ } else if (node->isElement("subform")) {
+ scanFormNode((ZxElement *)node, fullName, formValues);
+ }
+ }
+ }
+ delete fullNameIdx;
+}
+
+void XFAScanner::scanNode(ZxElement *elem,
+ GString *parentName, GString *parentFullName,
+ GHash *nameIdx, GHash *fullNameIdx,
+ GString *exclGroupName, ZxElement *dataElem,
+ GHash *formValues) {
+ GString *nodeName = getNodeName(elem);
+ GHash *childNameIdx;
+ if (!nameIdx || nodeName) {
+ childNameIdx = new GHash();
+ } else {
+ childNameIdx = nameIdx;
+ }
+ GString *nodeFullName = getNodeFullName(elem);
+ GHash *childFullNameIdx;
+ if (!fullNameIdx || (nodeFullName && !elem->isElement("area"))) {
+ childFullNameIdx = new GHash();
+ } else {
+ childFullNameIdx = fullNameIdx;
+ }
+
+ GString *childName;
+ if (nodeName) {
+ if (parentName) {
+ childName = GString::format("{0:t}.{1:t}", parentName, nodeName);
+ } else {
+ childName = nodeName->copy();
+ }
+ int idx = nameIdx->lookupInt(nodeName);
+ nameIdx->replace(nodeName, idx + 1);
+ if (nodeIsBindGlobal(elem)) {
+ childName->appendf("[0]");
+ } else {
+ childName->appendf("[{0:d}]", idx);
+ }
+ } else {
+ childName = parentName;
+ }
+ GString *childFullName;
+ if (nodeFullName) {
+ if (parentFullName) {
+ childFullName = GString::format("{0:t}.{1:t}",
+ parentFullName, nodeFullName);
+ } else {
+ childFullName = nodeFullName->copy();
+ }
+ int idx = fullNameIdx->lookupInt(nodeFullName);
+ fullNameIdx->replace(nodeFullName, idx + 1);
+ childFullName->appendf("[{0:d}]", idx);
+ } else {
+ childFullName = parentFullName;
+ }
+
+ if (elem->isElement("field")) {
+ scanField(elem, childName, childFullName, exclGroupName,
+ dataElem, formValues);
+ } else {
+ GString *childExclGroupName;
+ if (elem->isElement("exclGroup")) {
+ childExclGroupName = childName;
+ } else {
+ childExclGroupName = NULL;
+ }
+ for (ZxNode *child = elem->getFirstChild();
+ child;
+ child = child->getNextChild()) {
+ if (child->isElement()) {
+ scanNode((ZxElement *)child, childName, childFullName,
+ childNameIdx, childFullNameIdx, childExclGroupName,
+ dataElem, formValues);
+ }
+ }
+ }
+
+ if (childName != parentName) {
+ delete childName;
+ }
+ if (childFullName != parentFullName) {
+ delete childFullName;
+ }
+ if (childNameIdx != nameIdx) {
+ delete childNameIdx;
+ }
+ if (childFullNameIdx != fullNameIdx) {
+ delete childFullNameIdx;
+ }
+}
+
+void XFAScanner::scanField(ZxElement *elem, GString *name, GString *fullName,
+ GString *exclGroupName, ZxElement *dataElem,
+ GHash *formValues) {
+ GString *value = getFieldValue(elem, name, fullName, exclGroupName,
+ dataElem, formValues);
+ XFAFieldLayoutInfo *layoutInfo = getFieldLayoutInfo(elem);
+ XFAFieldPictureInfo *pictureInfo = getFieldPictureInfo(elem);
+ XFAFieldBarcodeInfo *barcodeInfo = getFieldBarcodeInfo(elem);
+ XFAField *field = new XFAField(name->copy(), fullName->copy(), value,
+ layoutInfo, pictureInfo, barcodeInfo);
+ fields->add(field->fullName, field);
+}
+
+GString *XFAScanner::getFieldValue(ZxElement *elem, GString *name,
+ GString *fullName, GString *exclGroupName,
+ ZxElement *dataElem, GHash *formValues) {
+ GString *val = NULL;
+
+ //--- check the <xfa:datasets> packet
+ val = getDatasetsValue(name->getCString(), dataElem);
+ if (!val && exclGroupName) {
+ val = (GString *)getDatasetsValue(exclGroupName->getCString(), dataElem);
+ }
+
+ //--- check the <form> element
+ if (!val) {
+ val = (GString *)formValues->lookup(fullName);
+ }
+
+ //--- check the <value> element within the field
+ if (!val) {
+ ZxElement *valueElem = elem->findFirstChildElement("value");
+ if (valueElem) {
+ ZxNode *child1Node = valueElem->getFirstChild();
+ if (child1Node && child1Node->isElement()) {
+ ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
+ if (child2Node && child2Node->isCharData()) {
+ val = ((ZxCharData *)child2Node)->getData();
+ }
+ }
+ }
+ }
+
+ //--- get the checkbutton item value
+ GString *checkbuttonItem = NULL;
+ ZxElement *uiElem = elem->findFirstChildElement("ui");
+ if (uiElem) {
+ ZxNode *uiChild = uiElem->getFirstChild();
+ if (uiChild && uiChild->isElement("checkButton")) {
+ ZxElement *itemsElem = elem->findFirstChildElement("items");
+ if (itemsElem) {
+ ZxNode *node1 = itemsElem->getFirstChild();
+ if (node1 && node1->isElement()) {
+ ZxNode *node2 = ((ZxElement *)node1)->getFirstChild();
+ if (node2 && node2->isCharData()) {
+ checkbuttonItem = ((ZxCharData *)node2)->getData();
+ }
+ }
+ }
+ }
+ }
+ // convert XFA checkbutton value to AcroForm-style On/Off value
+ if (checkbuttonItem && val) {
+ if (val->cmp(checkbuttonItem)) {
+ val = new GString("Off");
+ } else {
+ val = new GString("On");
+ }
+ } else if (val) {
+ val = val->copy();
+ }
+
+ return val;
+}
+
+GString *XFAScanner::getDatasetsValue(char *partName, ZxElement *elem) {
+ if (!elem) {
+ return NULL;
+ }
+
+ // partName = xxxx[nn].yyyy----
+ char *p = strchr(partName, '[');
+ if (!p) {
+ return NULL;
+ }
+ int partLen = (int)(p - partName);
+ int idx = atoi(p + 1);
+ p = strchr(p + 1, '.');
+ if (p) {
+ ++p;
+ }
+
+ int curIdx = 0;
+ for (ZxNode *node = elem->getFirstChild();
+ node;
+ node = node->getNextChild()) {
+ if (!node->isElement()) {
+ continue;
+ }
+ GString *nodeName = ((ZxElement *)node)->getType();
+ if (nodeName->getLength() != partLen ||
+ strncmp(nodeName->getCString(), partName, partLen)) {
+ continue;
+ }
+ if (curIdx != idx) {
+ ++curIdx;
+ continue;
+ }
+ if (p) {
+ GString *val = getDatasetsValue(p, (ZxElement *)node);
+ if (val) {
+ return val;
+ }
+ break;
+ } else {
+ ZxNode *child = ((ZxElement *)node)->getFirstChild();
+ if (!child || !child->isCharData()) {
+ return NULL;
+ }
+ return ((ZxCharData *)child)->getData();
+ }
+ }
+
+ // search for an 'ancestor match'
+ if (p) {
+ return getDatasetsValue(p, elem);
+ }
+
+ return NULL;
+}
+
+XFAFieldLayoutInfo *XFAScanner::getFieldLayoutInfo(ZxElement *elem) {
+ ZxElement *paraElem = elem->findFirstChildElement("para");
+ if (!paraElem) {
+ return NULL;
+ }
+ XFAFieldLayoutHAlign hAlign = xfaFieldLayoutHAlignLeft;
+ ZxAttr *hAlignAttr = paraElem->findAttr("hAlign");
+ if (hAlignAttr) {
+ if (!hAlignAttr->getValue()->cmp("left")) {
+ hAlign = xfaFieldLayoutHAlignLeft;
+ } else if (!hAlignAttr->getValue()->cmp("center")) {
+ hAlign = xfaFieldLayoutHAlignCenter;
+ } else if (!hAlignAttr->getValue()->cmp("right")) {
+ hAlign = xfaFieldLayoutHAlignRight;
+ }
+ }
+ XFAFieldLayoutVAlign vAlign = xfaFieldLayoutVAlignTop;
+ ZxAttr *vAlignAttr = paraElem->findAttr("vAlign");
+ if (vAlignAttr) {
+ if (!vAlignAttr->getValue()->cmp("top")) {
+ vAlign = xfaFieldLayoutVAlignTop;
+ } else if (!vAlignAttr->getValue()->cmp("middle")) {
+ vAlign = xfaFieldLayoutVAlignMiddle;
+ } else if (!vAlignAttr->getValue()->cmp("bottom")) {
+ vAlign = xfaFieldLayoutVAlignBottom;
+ }
+ }
+ return new XFAFieldLayoutInfo(hAlign, vAlign);
+}
+
+XFAFieldPictureInfo *XFAScanner::getFieldPictureInfo(ZxElement *elem) {
+ ZxElement *uiElem = elem->findFirstChildElement("ui");
+ if (!uiElem) {
+ return NULL;
+ }
+ XFAFieldPictureSubtype subtype;
+ if (uiElem->findFirstChildElement("dateTimeEdit")) {
+ subtype = xfaFieldPictureDateTime;
+ } else if (uiElem->findFirstChildElement("numericEdit")) {
+ subtype = xfaFieldPictureNumeric;
+ } else if (uiElem->findFirstChildElement("textEdit")) {
+ subtype = xfaFieldPictureText;
+ } else {
+ return NULL;
+ }
+
+ ZxElement *formatElem, *pictureElem;
+ ZxNode *pictureChildNode;
+ if (!(formatElem = elem->findFirstChildElement("format")) ||
+ !(pictureElem = formatElem->findFirstChildElement("picture")) ||
+ !(pictureChildNode = pictureElem->getFirstChild()) ||
+ !pictureChildNode->isCharData()) {
+ return NULL;
+ }
+ GString *format = ((ZxCharData *)pictureChildNode)->getData()->copy();
+
+ return new XFAFieldPictureInfo(subtype, format);
+}
+
+XFAFieldBarcodeInfo *XFAScanner::getFieldBarcodeInfo(ZxElement *elem) {
+ ZxElement *uiElem, *barcodeElem;
+ if (!(uiElem = elem->findFirstChildElement("ui")) ||
+ !(barcodeElem = uiElem->findFirstChildElement("barcode"))) {
+ return NULL;
+ }
+
+ ZxAttr *attr;
+ if (!(attr = barcodeElem->findAttr("type"))) {
+ return NULL;
+ }
+ GString *barcodeType = attr->getValue()->copy();
+
+ double wideNarrowRatio = 3;
+ if ((attr = barcodeElem->findAttr("wideNarrowRatio"))) {
+ char *s = attr->getValue()->getCString();
+ char *colon = strchr(s, ':');
+ if (colon) {
+ GString *numStr = new GString(s, (int)(colon - s));
+ double num = atof(numStr->getCString());
+ delete numStr;
+ double den = atof(colon + 1);
+ if (den == 0) {
+ wideNarrowRatio = num;
+ } else {
+ wideNarrowRatio = num / den;
+ }
+ } else {
+ wideNarrowRatio = atof(s);
+ }
+ }
+
+ double moduleWidth = (0.25 / 25.4) * 72.0; // 0.25mm
+ if ((attr = barcodeElem->findAttr("moduleWidth"))) {
+ moduleWidth = getMeasurement(attr->getValue());
+ }
+
+ double moduleHeight = (5.0 / 25.4) * 72.0; // 5mm
+ if ((attr = barcodeElem->findAttr("moduleHeight"))) {
+ moduleHeight = getMeasurement(attr->getValue());
+ }
+
+ int dataLength = 0;
+ if ((attr = barcodeElem->findAttr("dataLength"))) {
+ dataLength = atoi(attr->getValue()->getCString());
+ }
+
+ int errorCorrectionLevel = 0;
+ if ((attr = barcodeElem->findAttr("errorCorrectionLevel"))) {
+ errorCorrectionLevel = atoi(attr->getValue()->getCString());
+ }
+
+ GString *textLocation;
+ if ((attr = barcodeElem->findAttr("textLocation"))) {
+ textLocation = attr->getValue()->copy();
+ } else {
+ textLocation = new GString("below");
+ }
+
+ return new XFAFieldBarcodeInfo(barcodeType, wideNarrowRatio,
+ moduleWidth, moduleHeight, dataLength,
+ errorCorrectionLevel, textLocation);
+}
+
+double XFAScanner::getMeasurement(GString *s) {
+ int i = 0;
+ GBool neg = gFalse;
+ if (i < s->getLength() && s->getChar(i) == '+') {
+ ++i;
+ } else if (i < s->getLength() && s->getChar(i) == '-') {
+ neg = gTrue;
+ ++i;
+ }
+ double val = 0;
+ while (i < s->getLength() && s->getChar(i) >= '0' && s->getChar(i) <= '9') {
+ val = val * 10 + s->getChar(i) - '0';
+ ++i;
+ }
+ if (i < s->getLength() && s->getChar(i) == '.') {
+ ++i;
+ double mul = 0.1;
+ while (i < s->getLength() &&
+ s->getChar(i) >= '0' && s->getChar(i) <= '9') {
+ val += mul * (s->getChar(i) - '0');
+ mul *= 0.1;
+ ++i;
+ }
+ }
+ if (neg) {
+ val = -val;
+ }
+ if (i+1 < s->getLength()) {
+ if (s->getChar(i) == 'i' && s->getChar(i+1) == 'n') {
+ val *= 72;
+ } else if (s->getChar(i) == 'p' && s->getChar(i+1) == 't') {
+ // no change
+ } else if (s->getChar(i) == 'c' && s->getChar(i+1) == 'm') {
+ val *= 72 / 2.54;
+ } else if (s->getChar(i) == 'm' && s->getChar(i+1) == 'm') {
+ val *= 72 / 25.4;
+ } else {
+ // default to inches
+ val *= 72;
+ }
+ } else {
+ // default to inches
+ val *= 72;
+ }
+ return val;
+}
+
+GString *XFAScanner::getNodeName(ZxElement *elem) {
+ if (elem->isElement("template") ||
+ elem->isElement("area") ||
+ elem->isElement("draw")) {
+ return NULL;
+ }
+ if (!elem->isElement("field") && nodeIsBindNone(elem)) {
+ return NULL;
+ }
+ ZxAttr *nameAttr = elem->findAttr("name");
+ if (!nameAttr) {
+ return NULL;
+ }
+ return nameAttr->getValue();
+}
+
+GString *XFAScanner::getNodeFullName(ZxElement *elem) {
+ if (elem->isElement("template") ||
+ elem->isElement("draw")) {
+ return NULL;
+ }
+ ZxAttr *nameAttr = elem->findAttr("name");
+ if (!nameAttr) {
+ return NULL;
+ }
+ return nameAttr->getValue();
+}
+
+GBool XFAScanner::nodeIsBindGlobal(ZxElement *elem) {
+ ZxElement *bindElem = elem->findFirstChildElement("bind");
+ if (!bindElem) {
+ return gFalse;
+ }
+ ZxAttr *attr = bindElem->findAttr("match");
+ return attr && !attr->getValue()->cmp("global");
+}
+
+GBool XFAScanner::nodeIsBindNone(ZxElement *elem) {
+ ZxElement *bindElem = elem->findFirstChildElement("bind");
+ if (!bindElem) {
+ return gFalse;
+ }
+ ZxAttr *attr = bindElem->findAttr("match");
+ return attr && !attr->getValue()->cmp("none");
+}