Coverage Report

Created: 2025-10-10 08:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.05/xpdf/XFAScanner.cc
Line
Count
Source
1
//========================================================================
2
//
3
// XFAScanner.cc
4
//
5
// Copyright 2020 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include "GString.h"
12
#include "GHash.h"
13
#include "Object.h"
14
#include "Error.h"
15
#include "Zoox.h"
16
#include "XFAScanner.h"
17
18
//------------------------------------------------------------------------
19
20
// fields have two names:
21
//
22
// name:
23
//   - nodes with bind=global set the index to 0 ("foo[0]") regardless
24
//     of the number of nodes with the same name
25
//   - nodes with bind=none are dropped from the name
26
//   - <area> nodes are dropped from the name
27
//   - used for field value lookup in <xfa:datasets>
28
//
29
// fullName:
30
//   - all named nodes are treated the same, regardless of bind=global
31
//     or bind=none
32
//   - <area> nodes are included in the name, but don't reset the
33
//     numbering (i.e., <area> nodes are "transparent" with respect to
34
//     node numbering)
35
//   - used for field value lookup in <form>
36
//   - used for matching with AcroForm names
37
//
38
// Both names use indexes on all nodes, even if there's only one node
39
// with the name -- this isn't correct for XFA naming, but it matches
40
// the AcroForm behavior.
41
42
//------------------------------------------------------------------------
43
44
XFAFieldLayoutInfo::XFAFieldLayoutInfo(XFAFieldLayoutHAlign hAlignA,
45
1.30k
               XFAFieldLayoutVAlign vAlignA) {
46
1.30k
  hAlign = hAlignA;
47
1.30k
  vAlign = vAlignA;
48
1.30k
}
49
50
//------------------------------------------------------------------------
51
52
XFAFieldPictureInfo::XFAFieldPictureInfo(XFAFieldPictureSubtype subtypeA,
53
0
           GString *formatA) {
54
0
  subtype = subtypeA;
55
0
  format = formatA;
56
0
}
57
58
0
XFAFieldPictureInfo::~XFAFieldPictureInfo() {
59
0
  delete format;
60
0
}
61
62
//------------------------------------------------------------------------
63
64
XFAFieldBarcodeInfo::XFAFieldBarcodeInfo(GString *barcodeTypeA,
65
           double wideNarrowRatioA,
66
           double moduleWidthA,
67
           double moduleHeightA,
68
           int dataLengthA,
69
           int errorCorrectionLevelA,
70
0
           GString *textLocationA) {
71
0
  barcodeType = barcodeTypeA;
72
0
  wideNarrowRatio = wideNarrowRatioA;
73
0
  moduleWidth = moduleWidthA;
74
0
  moduleHeight = moduleHeightA;
75
0
  dataLength = dataLengthA;
76
0
  errorCorrectionLevel = errorCorrectionLevelA;
77
0
  textLocation = textLocationA;
78
0
}
79
80
0
XFAFieldBarcodeInfo::~XFAFieldBarcodeInfo() {
81
0
  delete barcodeType;
82
0
  delete textLocation;
83
0
}
84
85
//------------------------------------------------------------------------
86
87
XFAField::XFAField(GString *nameA, GString *fullNameA, GString *valueA,
88
       XFAFieldLayoutInfo *layoutInfoA,
89
       XFAFieldPictureInfo *pictureInfoA,
90
       XFAFieldBarcodeInfo *barcodeInfoA)
91
4.45k
  : name(nameA)
92
4.45k
  , fullName(fullNameA)
93
4.45k
  , value(valueA)
94
4.45k
  , layoutInfo(layoutInfoA)
95
4.45k
  , pictureInfo(pictureInfoA)
96
4.45k
  , barcodeInfo(barcodeInfoA)
97
4.45k
{
98
4.45k
}
99
100
4.45k
XFAField::~XFAField() {
101
4.45k
  delete name;
102
4.45k
  delete fullName;
103
4.45k
  delete value;
104
4.45k
  delete layoutInfo;
105
4.45k
  delete pictureInfo;
106
4.45k
  delete barcodeInfo;
107
4.45k
}
108
109
//------------------------------------------------------------------------
110
111
950
XFAScanner *XFAScanner::load(Object *xfaObj) {
112
950
  GString *xfaData = readXFAStreams(xfaObj);
113
950
  if (!xfaData) {
114
26
    return NULL;
115
26
  }
116
924
  ZxDoc *xml = ZxDoc::loadMem(xfaData->getCString(), xfaData->getLength());
117
924
  delete xfaData;
118
924
  if (!xml) {
119
197
    error(errSyntaxError, -1, "Invalid XML in XFA form");
120
197
    return NULL;
121
197
  }
122
123
727
  XFAScanner *scanner = new XFAScanner();
124
125
727
  if (xml->getRoot()) {
126
727
    GHash *formValues = scanner->scanFormValues(xml->getRoot());
127
727
    ZxElement *dataElem = NULL;
128
727
    ZxElement *datasets =
129
727
        xml->getRoot()->findFirstChildElement("xfa:datasets");
130
727
    if (datasets) {
131
63
      dataElem = datasets->findFirstChildElement("xfa:data");
132
63
    }
133
727
    ZxElement *tmpl = xml->getRoot()->findFirstChildElement("template");
134
727
    if (tmpl) {
135
345
      scanner->scanNode(tmpl, NULL, NULL, NULL, NULL, NULL,
136
345
      dataElem, formValues);
137
345
    }
138
727
    deleteGHash(formValues, GString);
139
727
  }
140
141
727
  delete xml;
142
143
727
  return scanner;
144
924
}
145
146
727
XFAScanner::XFAScanner() {
147
727
  fields = new GHash();
148
727
}
149
150
727
XFAScanner::~XFAScanner() {
151
727
  deleteGHash(fields, XFAField);
152
727
}
153
154
146
XFAField *XFAScanner::findField(GString *acroFormFieldName) {
155
146
  return (XFAField *)fields->lookup(acroFormFieldName);
156
146
}
157
158
950
GString *XFAScanner::readXFAStreams(Object *xfaObj) {
159
950
  GString *data = new GString();
160
950
  char buf[4096];
161
950
  int n;
162
950
  if (xfaObj->isStream()) {
163
0
    xfaObj->streamReset();
164
0
    while ((n = xfaObj->getStream()->getBlock(buf, sizeof(buf))) > 0) {
165
0
      data->append(buf, n);
166
0
    }
167
950
  } else if (xfaObj->isArray()) {
168
5.13k
    for (int i = 1; i < xfaObj->arrayGetLength(); i += 2) {
169
4.21k
      Object obj;
170
4.21k
      if (!xfaObj->arrayGet(i, &obj)->isStream()) {
171
26
  error(errSyntaxError, -1, "XFA array element is wrong type");
172
26
  obj.free();
173
26
  delete data;
174
26
  return NULL;
175
26
      }
176
4.18k
      obj.streamReset();
177
43.8k
      while ((n = obj.getStream()->getBlock(buf, sizeof(buf))) > 0) {
178
39.7k
  data->append(buf, n);
179
39.7k
      }
180
4.18k
      obj.free();
181
4.18k
    }
182
950
  } else {
183
0
    error(errSyntaxError, -1, "XFA object is wrong type");
184
0
    return NULL;
185
0
  }
186
924
  return data;
187
950
}
188
189
727
GHash *XFAScanner::scanFormValues(ZxElement *xmlRoot) {
190
727
  GHash *formValues = new GHash(gTrue);
191
727
  ZxElement *formElem = xmlRoot->findFirstChildElement("form");
192
727
  if (formElem) {
193
20
    scanFormNode(formElem, NULL, formValues);
194
20
  }
195
727
  return formValues;
196
727
}
197
198
void XFAScanner::scanFormNode(ZxElement *elem, GString *fullName,
199
20
            GHash *formValues) {
200
20
  GHash *fullNameIdx = new GHash();
201
20
  for (ZxNode *node = elem->getFirstChild();
202
279
       node;
203
259
       node = node->getNextChild()) {
204
259
    if (node->isElement("value")) {
205
0
      if (fullName) {
206
0
  ZxNode *child1Node = ((ZxElement *)node)->getFirstChild();
207
0
  if (child1Node && child1Node->isElement()) {
208
0
    ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
209
0
    if (child2Node && child2Node->isCharData()) {
210
0
      formValues->add(fullName->copy(),
211
0
          ((ZxCharData *)child2Node)->getData()->copy());
212
0
    }
213
0
  }
214
0
      }
215
259
    } else if (node->isElement()) {
216
117
      ZxAttr *nameAttr = ((ZxElement *)node)->findAttr("name");
217
117
      if (nameAttr && (node->isElement("subform") ||
218
0
           node->isElement("field"))) {
219
0
  GString *nodeName = nameAttr->getValue();
220
0
  GString *childFullName;
221
0
  if (fullName) {
222
0
    childFullName = GString::format("{0:t}.{1:t}", fullName, nodeName);
223
0
  } else {
224
0
    childFullName = nodeName->copy();
225
0
  }
226
0
  int idx = fullNameIdx->lookupInt(nodeName);
227
0
  childFullName->appendf("[{0:d}]", idx);
228
0
  fullNameIdx->replace(nodeName, idx + 1);
229
0
  scanFormNode((ZxElement *)node, childFullName, formValues);
230
0
  delete childFullName;
231
117
      } else if (node->isElement("subform")) {
232
0
  scanFormNode((ZxElement *)node, fullName, formValues);
233
0
      }
234
117
    }
235
259
  }
236
20
  delete fullNameIdx;
237
20
}
238
239
void XFAScanner::scanNode(ZxElement *elem,
240
        GString *parentName, GString *parentFullName,
241
        GHash *nameIdx, GHash *fullNameIdx,
242
        GString *exclGroupName, ZxElement *dataElem,
243
133k
        GHash *formValues) {
244
133k
  GString *nodeName = getNodeName(elem);
245
133k
  GHash *childNameIdx;
246
133k
  if (!nameIdx || nodeName) {
247
21.7k
    childNameIdx = new GHash();
248
111k
  } else {
249
111k
    childNameIdx = nameIdx;
250
111k
  }
251
133k
  GString *nodeFullName = getNodeFullName(elem);
252
133k
  GHash *childFullNameIdx;
253
133k
  if (!fullNameIdx || (nodeFullName && !elem->isElement("area"))) {
254
21.7k
    childFullNameIdx = new GHash();
255
111k
  } else {
256
111k
    childFullNameIdx = fullNameIdx;
257
111k
  }
258
259
133k
  GString *childName;
260
133k
  if (nodeName) {
261
21.4k
    if (parentName) {
262
18.5k
      childName = GString::format("{0:t}.{1:t}", parentName, nodeName);
263
18.5k
    } else {
264
2.89k
      childName = nodeName->copy();
265
2.89k
    }
266
21.4k
    int idx = nameIdx->lookupInt(nodeName);
267
21.4k
    nameIdx->replace(nodeName, idx + 1);
268
21.4k
    if (nodeIsBindGlobal(elem)) {
269
0
      childName->appendf("[0]");
270
21.4k
    } else {
271
21.4k
      childName->appendf("[{0:d}]", idx);
272
21.4k
    }
273
112k
  } else {
274
112k
    childName = parentName;
275
112k
  }
276
133k
  GString *childFullName;
277
133k
  if (nodeFullName) {
278
21.4k
    if (parentFullName) {
279
18.5k
      childFullName = GString::format("{0:t}.{1:t}",
280
18.5k
              parentFullName, nodeFullName);
281
18.5k
    } else {
282
2.89k
      childFullName = nodeFullName->copy();
283
2.89k
    }
284
21.4k
    int idx = fullNameIdx->lookupInt(nodeFullName);
285
21.4k
    fullNameIdx->replace(nodeFullName, idx + 1);
286
21.4k
    childFullName->appendf("[{0:d}]", idx);
287
112k
  } else {
288
112k
    childFullName = parentFullName;
289
112k
  }
290
291
133k
  if (elem->isElement("field")) {
292
4.77k
    if (childName && childFullName) {
293
4.45k
      scanField(elem, childName, childFullName, exclGroupName,
294
4.45k
    dataElem, formValues);
295
4.45k
    }
296
128k
  } else {
297
128k
    GString *childExclGroupName;
298
128k
    if (elem->isElement("exclGroup")) {
299
501
      childExclGroupName = childName;
300
128k
    } else {
301
128k
      childExclGroupName = NULL;
302
128k
    }
303
128k
    for (ZxNode *child = elem->getFirstChild();
304
363k
   child;
305
235k
   child = child->getNextChild()) {
306
235k
      if (child->isElement()) {
307
133k
  scanNode((ZxElement *)child, childName, childFullName,
308
133k
     childNameIdx, childFullNameIdx, childExclGroupName,
309
133k
     dataElem, formValues);
310
133k
      }
311
235k
    }
312
128k
  }
313
314
133k
  if (childName != parentName) {
315
21.4k
    delete childName;
316
21.4k
  }
317
133k
  if (childFullName != parentFullName) {
318
21.4k
    delete childFullName;
319
21.4k
  }
320
133k
  if (childNameIdx != nameIdx) {
321
21.7k
    delete childNameIdx;
322
21.7k
  }
323
133k
  if (childFullNameIdx != fullNameIdx) {
324
21.7k
    delete childFullNameIdx;
325
21.7k
  }
326
133k
}
327
328
void XFAScanner::scanField(ZxElement *elem, GString *name, GString *fullName,
329
         GString *exclGroupName, ZxElement *dataElem,
330
4.45k
         GHash *formValues) {
331
4.45k
  GString *value = getFieldValue(elem, name, fullName, exclGroupName,
332
4.45k
         dataElem, formValues);
333
4.45k
  XFAFieldLayoutInfo *layoutInfo = getFieldLayoutInfo(elem);
334
4.45k
  XFAFieldPictureInfo *pictureInfo = getFieldPictureInfo(elem);
335
4.45k
  XFAFieldBarcodeInfo *barcodeInfo = getFieldBarcodeInfo(elem);
336
4.45k
  XFAField *field = new XFAField(name->copy(), fullName->copy(), value,
337
4.45k
         layoutInfo, pictureInfo, barcodeInfo);
338
4.45k
  fields->add(field->fullName, field);
339
4.45k
}
340
341
GString *XFAScanner::getFieldValue(ZxElement *elem, GString *name,
342
           GString *fullName, GString *exclGroupName,
343
4.45k
           ZxElement *dataElem, GHash *formValues) {
344
4.45k
  GString *val = NULL;
345
346
  //--- check the <xfa:datasets> packet
347
4.45k
  val = getDatasetsValue(name->getCString(), dataElem);
348
4.45k
  if (!val && exclGroupName) {
349
577
    val = (GString *)getDatasetsValue(exclGroupName->getCString(), dataElem);
350
577
  }
351
352
  //--- check the <form> element
353
4.45k
  if (!val) {
354
4.29k
    val = (GString *)formValues->lookup(fullName);
355
4.29k
  }
356
357
  //--- check the <value> element within the field
358
4.45k
  if (!val) {
359
4.29k
    ZxElement *valueElem = elem->findFirstChildElement("value");
360
4.29k
    if (valueElem) {
361
1.22k
      ZxNode *child1Node = valueElem->getFirstChild();
362
1.22k
      if (child1Node && child1Node->isElement()) {
363
1.15k
  ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
364
1.15k
  if (child2Node && child2Node->isCharData()) {
365
189
    val = ((ZxCharData *)child2Node)->getData();
366
189
  }
367
1.15k
      }
368
1.22k
    }
369
4.29k
  }
370
371
  //--- get the checkbutton item value
372
4.45k
  GString *checkbuttonItem = NULL;
373
4.45k
  ZxElement *uiElem = elem->findFirstChildElement("ui");
374
4.45k
  if (uiElem) {
375
1.58k
    ZxNode *uiChild = uiElem->getFirstChild();
376
1.58k
    if (uiChild && uiChild->isElement("checkButton")) {
377
1.26k
      ZxElement *itemsElem = elem->findFirstChildElement("items");
378
1.26k
      if (itemsElem) {
379
1.02k
  ZxNode *node1 = itemsElem->getFirstChild();
380
1.02k
  if (node1 && node1->isElement()) {
381
994
    ZxNode *node2 = ((ZxElement *)node1)->getFirstChild();
382
994
    if (node2 && node2->isCharData()) {
383
127
      checkbuttonItem = ((ZxCharData *)node2)->getData();
384
127
    }
385
994
  }
386
1.02k
      }
387
1.26k
    }
388
1.58k
  }
389
  // convert XFA checkbutton value to AcroForm-style On/Off value
390
4.45k
  if (checkbuttonItem && val) {
391
107
    if (val->cmp(checkbuttonItem)) {
392
89
      val = new GString("Off");
393
89
    } else {
394
18
      val = new GString("On");
395
18
    }
396
4.34k
  } else if (val) {
397
239
    val = val->copy();
398
239
  }
399
400
4.45k
  return val;
401
4.45k
}
402
403
37.5k
GString *XFAScanner::getDatasetsValue(char *partName, ZxElement *elem) {
404
37.5k
  if (!elem) {
405
3.39k
    return NULL;
406
3.39k
  }
407
408
  // partName = xxxx[nn].yyyy----
409
34.1k
  char *p = strchr(partName, '[');
410
34.1k
  if (!p) {
411
621
    return NULL;
412
621
  }
413
33.5k
  int partLen = (int)(p - partName);
414
33.5k
  int idx = atoi(p + 1);
415
33.5k
  p = strchr(p + 1, '.');
416
33.5k
  if (p) {
417
28.3k
    ++p;
418
28.3k
  }
419
420
33.5k
  int curIdx = 0;
421
33.5k
  for (ZxNode *node = elem->getFirstChild();
422
229k
       node;
423
200k
       node = node->getNextChild()) {
424
200k
    if (!node->isElement()) {
425
28.4k
      continue;
426
28.4k
    }
427
172k
    GString *nodeName = ((ZxElement *)node)->getType();
428
172k
    if (nodeName->getLength() != partLen ||
429
164k
  strncmp(nodeName->getCString(), partName, partLen)) {
430
164k
      continue;
431
164k
    }
432
7.91k
    if (curIdx != idx) {
433
3.18k
      ++curIdx;
434
3.18k
      continue;
435
3.18k
    }
436
4.73k
    if (p) {
437
4.28k
      GString *val = getDatasetsValue(p, (ZxElement *)node);
438
4.28k
      if (val) {
439
146
  return val;
440
146
      }
441
4.14k
      break;
442
4.28k
    } else {
443
448
      ZxNode *child = ((ZxElement *)node)->getFirstChild();
444
448
      if (!child || !child->isCharData()) {
445
291
  return NULL;
446
291
      }
447
157
      return ((ZxCharData *)child)->getData();
448
448
    }
449
4.73k
  }
450
451
  // search for an 'ancestor match'
452
32.9k
  if (p) {
453
28.1k
    return getDatasetsValue(p, elem);
454
28.1k
  }
455
456
4.71k
  return NULL;
457
32.9k
}
458
459
4.45k
XFAFieldLayoutInfo *XFAScanner::getFieldLayoutInfo(ZxElement *elem) {
460
4.45k
  ZxElement *paraElem = elem->findFirstChildElement("para");
461
4.45k
  if (!paraElem) {
462
3.14k
    return NULL;
463
3.14k
  }
464
1.30k
  XFAFieldLayoutHAlign hAlign = xfaFieldLayoutHAlignLeft;
465
1.30k
  ZxAttr *hAlignAttr = paraElem->findAttr("hAlign");
466
1.30k
  if (hAlignAttr) {
467
10
    if (!hAlignAttr->getValue()->cmp("left")) {
468
0
      hAlign = xfaFieldLayoutHAlignLeft;
469
10
    } else if (!hAlignAttr->getValue()->cmp("center")) {
470
0
      hAlign = xfaFieldLayoutHAlignCenter;
471
10
    } else if (!hAlignAttr->getValue()->cmp("right")) {
472
0
      hAlign = xfaFieldLayoutHAlignRight;
473
0
    }
474
10
  }
475
1.30k
  XFAFieldLayoutVAlign vAlign = xfaFieldLayoutVAlignTop;
476
1.30k
  ZxAttr *vAlignAttr = paraElem->findAttr("vAlign");
477
1.30k
  if (vAlignAttr) {
478
346
    if (!vAlignAttr->getValue()->cmp("top")) {
479
0
      vAlign = xfaFieldLayoutVAlignTop;
480
346
    } else if (!vAlignAttr->getValue()->cmp("middle")) {
481
323
      vAlign = xfaFieldLayoutVAlignMiddle;
482
323
    } else if (!vAlignAttr->getValue()->cmp("bottom")) {
483
0
      vAlign = xfaFieldLayoutVAlignBottom;
484
0
    }
485
346
  }
486
1.30k
  return new XFAFieldLayoutInfo(hAlign, vAlign);
487
4.45k
}
488
489
4.45k
XFAFieldPictureInfo *XFAScanner::getFieldPictureInfo(ZxElement *elem) {
490
4.45k
  ZxElement *uiElem = elem->findFirstChildElement("ui");
491
4.45k
  if (!uiElem) {
492
2.86k
    return NULL;
493
2.86k
  }
494
1.58k
  XFAFieldPictureSubtype subtype;
495
1.58k
  if (uiElem->findFirstChildElement("dateTimeEdit")) {
496
0
    subtype = xfaFieldPictureDateTime;
497
1.58k
  } else if (uiElem->findFirstChildElement("numericEdit")) {
498
0
    subtype = xfaFieldPictureNumeric;
499
1.58k
  } else if (uiElem->findFirstChildElement("textEdit")) {
500
0
    subtype = xfaFieldPictureText;
501
1.58k
  } else {
502
1.58k
    return NULL;
503
1.58k
  }
504
505
0
  ZxElement *formatElem, *pictureElem;
506
0
  ZxNode *pictureChildNode;
507
0
  if (!(formatElem = elem->findFirstChildElement("format")) ||
508
0
      !(pictureElem = formatElem->findFirstChildElement("picture")) ||
509
0
      !(pictureChildNode = pictureElem->getFirstChild()) ||
510
0
      !pictureChildNode->isCharData()) {
511
0
    return NULL;
512
0
  }
513
0
  GString *format = ((ZxCharData *)pictureChildNode)->getData()->copy();
514
515
0
  return new XFAFieldPictureInfo(subtype, format);
516
0
}
517
518
4.45k
XFAFieldBarcodeInfo *XFAScanner::getFieldBarcodeInfo(ZxElement *elem) {
519
4.45k
  ZxElement *uiElem, *barcodeElem;
520
4.45k
  if (!(uiElem = elem->findFirstChildElement("ui")) ||
521
4.45k
      !(barcodeElem = uiElem->findFirstChildElement("barcode"))) {
522
4.45k
    return NULL;
523
4.45k
  }
524
525
0
  ZxAttr *attr;
526
0
  if (!(attr = barcodeElem->findAttr("type"))) {
527
0
    return NULL;
528
0
  }
529
0
  GString *barcodeType = attr->getValue()->copy();
530
531
0
  double wideNarrowRatio = 3;
532
0
  if ((attr = barcodeElem->findAttr("wideNarrowRatio"))) {
533
0
    char *s = attr->getValue()->getCString();
534
0
    char *colon = strchr(s, ':');
535
0
    if (colon) {
536
0
      GString *numStr = new GString(s, (int)(colon - s));
537
0
      double num = atof(numStr->getCString());
538
0
      delete numStr;
539
0
      double den = atof(colon + 1);
540
0
      if (den == 0) {
541
0
  wideNarrowRatio = num;
542
0
      } else {
543
0
  wideNarrowRatio = num / den;
544
0
      }
545
0
    } else {
546
0
      wideNarrowRatio = atof(s);
547
0
    }
548
0
  }
549
550
0
  double moduleWidth = (0.25 / 25.4) * 72.0; // 0.25mm
551
0
  if ((attr = barcodeElem->findAttr("moduleWidth"))) {
552
0
    moduleWidth = getMeasurement(attr->getValue());
553
0
  }
554
555
0
  double moduleHeight = (5.0 / 25.4) * 72.0; // 5mm
556
0
  if ((attr = barcodeElem->findAttr("moduleHeight"))) {
557
0
    moduleHeight = getMeasurement(attr->getValue());
558
0
  }
559
560
0
  int dataLength = 0;
561
0
  if ((attr = barcodeElem->findAttr("dataLength"))) {
562
0
    dataLength = atoi(attr->getValue()->getCString());
563
0
  }
564
565
0
  int errorCorrectionLevel = 0;
566
0
  if ((attr = barcodeElem->findAttr("errorCorrectionLevel"))) {
567
0
    errorCorrectionLevel = atoi(attr->getValue()->getCString());
568
0
  }
569
570
0
  GString *textLocation;
571
0
  if ((attr = barcodeElem->findAttr("textLocation"))) {
572
0
    textLocation = attr->getValue()->copy();
573
0
  } else {
574
0
    textLocation = new GString("below");
575
0
  }
576
577
0
  return new XFAFieldBarcodeInfo(barcodeType, wideNarrowRatio,
578
0
         moduleWidth, moduleHeight, dataLength,
579
0
         errorCorrectionLevel, textLocation);
580
0
}
581
582
0
double XFAScanner::getMeasurement(GString *s) {
583
0
  int i = 0;
584
0
  GBool neg = gFalse;
585
0
  if (i < s->getLength() && s->getChar(i) == '+') {
586
0
    ++i;
587
0
  } else if (i < s->getLength() && s->getChar(i) == '-') {
588
0
    neg = gTrue;
589
0
    ++i;
590
0
  }
591
0
  double val = 0;
592
0
  while (i < s->getLength() && s->getChar(i) >= '0' && s->getChar(i) <= '9') {
593
0
    val = val * 10 + s->getChar(i) - '0';
594
0
    ++i;
595
0
  }
596
0
  if (i < s->getLength() && s->getChar(i) == '.') {
597
0
    ++i;
598
0
    double mul = 0.1;
599
0
    while (i < s->getLength() &&
600
0
     s->getChar(i) >= '0' && s->getChar(i) <= '9') {
601
0
      val += mul * (s->getChar(i) - '0');
602
0
      mul *= 0.1;
603
0
      ++i;
604
0
    }
605
0
  }
606
0
  if (neg) {
607
0
    val = -val;
608
0
  }
609
0
  if (i+1 < s->getLength()) {
610
0
    if (s->getChar(i) == 'i' && s->getChar(i+1) == 'n') {
611
0
      val *= 72;
612
0
    } else if (s->getChar(i) == 'p' && s->getChar(i+1) == 't') {
613
      // no change
614
0
    } else if (s->getChar(i) == 'c' && s->getChar(i+1) == 'm') {
615
0
      val *= 72 / 2.54;
616
0
    } else if (s->getChar(i) == 'm' && s->getChar(i+1) == 'm') {
617
0
      val *= 72 / 25.4;
618
0
    } else {
619
      // default to inches
620
0
      val *= 72;
621
0
    }
622
0
  } else {
623
    // default to inches
624
0
    val *= 72;
625
0
  }
626
0
  return val;
627
0
}
628
629
133k
GString *XFAScanner::getNodeName(ZxElement *elem) {
630
133k
  if (elem->isElement("template") ||
631
132k
      elem->isElement("area") ||
632
132k
      elem->isElement("draw")) {
633
1.19k
    return NULL;
634
1.19k
  }
635
132k
  if (!elem->isElement("field") && nodeIsBindNone(elem)) {
636
0
    return NULL;
637
0
  }
638
132k
  ZxAttr *nameAttr = elem->findAttr("name");
639
132k
  if (!nameAttr) {
640
110k
    return NULL;
641
110k
  }
642
21.4k
  return nameAttr->getValue();
643
132k
}
644
645
133k
GString *XFAScanner::getNodeFullName(ZxElement *elem) {
646
133k
  if (elem->isElement("template") ||
647
132k
      elem->isElement("draw")) {
648
867
    return NULL;
649
867
  }
650
132k
  ZxAttr *nameAttr = elem->findAttr("name");
651
132k
  if (!nameAttr) {
652
111k
    return NULL;
653
111k
  }
654
21.4k
  return nameAttr->getValue();
655
132k
}
656
657
21.4k
GBool XFAScanner::nodeIsBindGlobal(ZxElement *elem) {
658
21.4k
  ZxElement *bindElem = elem->findFirstChildElement("bind");
659
21.4k
  if (!bindElem) {
660
21.4k
    return gFalse;
661
21.4k
  }
662
24
  ZxAttr *attr = bindElem->findAttr("match");
663
24
  return attr && !attr->getValue()->cmp("global");
664
21.4k
}
665
666
127k
GBool XFAScanner::nodeIsBindNone(ZxElement *elem) {
667
127k
  ZxElement *bindElem = elem->findFirstChildElement("bind");
668
127k
  if (!bindElem) {
669
127k
    return gFalse;
670
127k
  }
671
103
  ZxAttr *attr = bindElem->findAttr("match");
672
103
  return attr && !attr->getValue()->cmp("none");
673
127k
}