Coverage Report

Created: 2026-07-16 06:52

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