1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fxfa/parser/xfa_utils.h"
8
9#include "core/fxcrt/fx_ext.h"
10#include "xfa/fde/xml/fde_xml_imp.h"
11#include "xfa/fxfa/parser/cxfa_document.h"
12#include "xfa/fxfa/parser/cxfa_measurement.h"
13#include "xfa/fxfa/parser/xfa_basic_data.h"
14#include "xfa/fxfa/parser/xfa_localemgr.h"
15#include "xfa/fxfa/parser/xfa_localevalue.h"
16#include "xfa/fxfa/parser/xfa_object.h"
17
18namespace {
19
20const FX_DOUBLE fraction_scales[] = {0.1,
21                                     0.01,
22                                     0.001,
23                                     0.0001,
24                                     0.00001,
25                                     0.000001,
26                                     0.0000001,
27                                     0.00000001,
28                                     0.000000001,
29                                     0.0000000001,
30                                     0.00000000001,
31                                     0.000000000001,
32                                     0.0000000000001,
33                                     0.00000000000001,
34                                     0.000000000000001,
35                                     0.0000000000000001};
36
37FX_DOUBLE WideStringToDouble(const CFX_WideString& wsStringVal) {
38  CFX_WideString wsValue = wsStringVal;
39  wsValue.TrimLeft();
40  wsValue.TrimRight();
41  int64_t nIntegral = 0;
42  uint32_t dwFractional = 0;
43  int32_t nExponent = 0;
44  int32_t cc = 0;
45  bool bNegative = false;
46  bool bExpSign = false;
47  const FX_WCHAR* str = wsValue.c_str();
48  int32_t len = wsValue.GetLength();
49  if (str[0] == '+') {
50    cc++;
51  } else if (str[0] == '-') {
52    bNegative = true;
53    cc++;
54  }
55  int32_t nIntegralLen = 0;
56  while (cc < len) {
57    if (str[cc] == '.' || str[cc] == 'E' || str[cc] == 'e' ||
58        nIntegralLen > 17) {
59      break;
60    }
61    if (!FXSYS_isDecimalDigit(str[cc])) {
62      return 0;
63    }
64    nIntegral = nIntegral * 10 + str[cc] - '0';
65    cc++;
66    nIntegralLen++;
67  }
68  nIntegral = bNegative ? -nIntegral : nIntegral;
69  int32_t scale = 0;
70  FX_DOUBLE fraction = 0.0;
71  if (cc < len && str[cc] == '.') {
72    cc++;
73    while (cc < len) {
74      fraction += fraction_scales[scale] * (str[cc] - '0');
75      scale++;
76      cc++;
77      if (cc == len) {
78        break;
79      }
80      if (scale == sizeof(fraction_scales) / sizeof(FX_DOUBLE) ||
81          str[cc] == 'E' || str[cc] == 'e') {
82        break;
83      }
84      if (!FXSYS_isDecimalDigit(str[cc])) {
85        return 0;
86      }
87    }
88    dwFractional = (uint32_t)(fraction * 4294967296.0);
89  }
90  if (cc < len && (str[cc] == 'E' || str[cc] == 'e')) {
91    cc++;
92    if (cc < len) {
93      if (str[cc] == '+') {
94        cc++;
95      } else if (str[cc] == '-') {
96        bExpSign = true;
97        cc++;
98      }
99    }
100    while (cc < len) {
101      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc])) {
102        return 0;
103      }
104      nExponent = nExponent * 10 + str[cc] - '0';
105      cc++;
106    }
107    nExponent = bExpSign ? -nExponent : nExponent;
108  }
109  FX_DOUBLE dValue = (dwFractional / 4294967296.0);
110  dValue = nIntegral + (nIntegral >= 0 ? dValue : -dValue);
111  if (nExponent != 0) {
112    dValue *= FXSYS_pow(10, (FX_FLOAT)nExponent);
113  }
114  return dValue;
115}
116
117}  // namespace
118
119CXFA_LocaleValue XFA_GetLocaleValue(CXFA_WidgetData* pWidgetData) {
120  CXFA_Node* pNodeValue =
121      pWidgetData->GetNode()->GetChild(0, XFA_Element::Value);
122  if (!pNodeValue) {
123    return CXFA_LocaleValue();
124  }
125  CXFA_Node* pValueChild = pNodeValue->GetNodeItem(XFA_NODEITEM_FirstChild);
126  if (!pValueChild) {
127    return CXFA_LocaleValue();
128  }
129  int32_t iVTType = XFA_VT_NULL;
130  switch (pValueChild->GetElementType()) {
131    case XFA_Element::Decimal:
132      iVTType = XFA_VT_DECIMAL;
133      break;
134    case XFA_Element::Float:
135      iVTType = XFA_VT_FLOAT;
136      break;
137    case XFA_Element::Date:
138      iVTType = XFA_VT_DATE;
139      break;
140    case XFA_Element::Time:
141      iVTType = XFA_VT_TIME;
142      break;
143    case XFA_Element::DateTime:
144      iVTType = XFA_VT_DATETIME;
145      break;
146    case XFA_Element::Boolean:
147      iVTType = XFA_VT_BOOLEAN;
148      break;
149    case XFA_Element::Integer:
150      iVTType = XFA_VT_INTEGER;
151      break;
152    case XFA_Element::Text:
153      iVTType = XFA_VT_TEXT;
154      break;
155    default:
156      iVTType = XFA_VT_NULL;
157      break;
158  }
159  return CXFA_LocaleValue(iVTType, pWidgetData->GetRawValue(),
160                          pWidgetData->GetNode()->GetDocument()->GetLocalMgr());
161}
162void XFA_GetPlainTextFromRichText(CFDE_XMLNode* pXMLNode,
163                                  CFX_WideString& wsPlainText) {
164  if (!pXMLNode) {
165    return;
166  }
167  switch (pXMLNode->GetType()) {
168    case FDE_XMLNODE_Element: {
169      CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
170      CFX_WideString wsTag;
171      pXMLElement->GetLocalTagName(wsTag);
172      uint32_t uTag = FX_HashCode_GetW(wsTag.AsStringC(), true);
173      if (uTag == 0x0001f714) {
174        wsPlainText += L"\n";
175      } else if (uTag == 0x00000070) {
176        if (!wsPlainText.IsEmpty()) {
177          wsPlainText += L"\n";
178        }
179      } else if (uTag == 0xa48ac63) {
180        if (!wsPlainText.IsEmpty() &&
181            wsPlainText[wsPlainText.GetLength() - 1] != '\n') {
182          wsPlainText += L"\n";
183        }
184      }
185    } break;
186    case FDE_XMLNODE_Text: {
187      CFX_WideString wsContent;
188      static_cast<CFDE_XMLText*>(pXMLNode)->GetText(wsContent);
189      wsPlainText += wsContent;
190    } break;
191    case FDE_XMLNODE_CharData: {
192      CFX_WideString wsCharData;
193      static_cast<CFDE_XMLCharData*>(pXMLNode)->GetCharData(wsCharData);
194      wsPlainText += wsCharData;
195    } break;
196    default:
197      break;
198  }
199  for (CFDE_XMLNode* pChildXML =
200           pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
201       pChildXML;
202       pChildXML = pChildXML->GetNodeItem(CFDE_XMLNode::NextSibling)) {
203    XFA_GetPlainTextFromRichText(pChildXML, wsPlainText);
204  }
205}
206
207bool XFA_FieldIsMultiListBox(CXFA_Node* pFieldNode) {
208  bool bRet = false;
209  if (!pFieldNode)
210    return bRet;
211
212  CXFA_Node* pUIChild = pFieldNode->GetChild(0, XFA_Element::Ui);
213  if (pUIChild) {
214    CXFA_Node* pFirstChild = pUIChild->GetNodeItem(XFA_NODEITEM_FirstChild);
215    if (pFirstChild &&
216        pFirstChild->GetElementType() == XFA_Element::ChoiceList) {
217      bRet = pFirstChild->GetEnum(XFA_ATTRIBUTE_Open) ==
218             XFA_ATTRIBUTEENUM_MultiSelect;
219    }
220  }
221  return bRet;
222}
223
224FX_DOUBLE XFA_ByteStringToDouble(const CFX_ByteStringC& szStringVal) {
225  CFX_WideString wsValue = CFX_WideString::FromUTF8(szStringVal);
226  return WideStringToDouble(wsValue);
227}
228
229int32_t XFA_MapRotation(int32_t nRotation) {
230  nRotation = nRotation % 360;
231  nRotation = nRotation < 0 ? nRotation + 360 : nRotation;
232  return nRotation;
233}
234
235const XFA_SCRIPTATTRIBUTEINFO* XFA_GetScriptAttributeByName(
236    XFA_Element eElement,
237    const CFX_WideStringC& wsAttributeName) {
238  if (wsAttributeName.IsEmpty())
239    return nullptr;
240
241  int32_t iElementIndex = static_cast<int32_t>(eElement);
242  while (iElementIndex != -1) {
243    const XFA_SCRIPTHIERARCHY* scriptIndex = g_XFAScriptIndex + iElementIndex;
244    int32_t icount = scriptIndex->wAttributeCount;
245    if (icount == 0) {
246      iElementIndex = scriptIndex->wParentIndex;
247      continue;
248    }
249    uint32_t uHash = FX_HashCode_GetW(wsAttributeName, false);
250    int32_t iStart = scriptIndex->wAttributeStart, iEnd = iStart + icount - 1;
251    do {
252      int32_t iMid = (iStart + iEnd) / 2;
253      const XFA_SCRIPTATTRIBUTEINFO* pInfo = g_SomAttributeData + iMid;
254      if (uHash == pInfo->uHash)
255        return pInfo;
256      if (uHash < pInfo->uHash)
257        iEnd = iMid - 1;
258      else
259        iStart = iMid + 1;
260    } while (iStart <= iEnd);
261    iElementIndex = scriptIndex->wParentIndex;
262  }
263  return nullptr;
264}
265
266const XFA_NOTSUREATTRIBUTE* XFA_GetNotsureAttribute(XFA_Element eElement,
267                                                    XFA_ATTRIBUTE eAttribute,
268                                                    XFA_ATTRIBUTETYPE eType) {
269  int32_t iStart = 0, iEnd = g_iXFANotsureCount - 1;
270  do {
271    int32_t iMid = (iStart + iEnd) / 2;
272    const XFA_NOTSUREATTRIBUTE* pAttr = g_XFANotsureAttributes + iMid;
273    if (eElement == pAttr->eElement) {
274      if (pAttr->eAttribute == eAttribute) {
275        if (eType == XFA_ATTRIBUTETYPE_NOTSURE || eType == pAttr->eType)
276          return pAttr;
277        return nullptr;
278      }
279      int32_t iBefore = iMid - 1;
280      if (iBefore >= 0) {
281        pAttr = g_XFANotsureAttributes + iBefore;
282        while (eElement == pAttr->eElement) {
283          if (pAttr->eAttribute == eAttribute) {
284            if (eType == XFA_ATTRIBUTETYPE_NOTSURE || eType == pAttr->eType)
285              return pAttr;
286            return nullptr;
287          }
288          iBefore--;
289          if (iBefore < 0)
290            break;
291
292          pAttr = g_XFANotsureAttributes + iBefore;
293        }
294      }
295
296      int32_t iAfter = iMid + 1;
297      if (iAfter <= g_iXFANotsureCount - 1) {
298        pAttr = g_XFANotsureAttributes + iAfter;
299        while (eElement == pAttr->eElement) {
300          if (pAttr->eAttribute == eAttribute) {
301            if (eType == XFA_ATTRIBUTETYPE_NOTSURE || eType == pAttr->eType)
302              return pAttr;
303            return nullptr;
304          }
305          iAfter++;
306          if (iAfter > g_iXFANotsureCount - 1)
307            break;
308
309          pAttr = g_XFANotsureAttributes + iAfter;
310        }
311      }
312      return nullptr;
313    }
314
315    if (eElement < pAttr->eElement)
316      iEnd = iMid - 1;
317    else
318      iStart = iMid + 1;
319  } while (iStart <= iEnd);
320  return nullptr;
321}
322
323const XFA_PROPERTY* XFA_GetPropertyOfElement(XFA_Element eElement,
324                                             XFA_Element eProperty,
325                                             uint32_t dwPacket) {
326  int32_t iCount = 0;
327  const XFA_PROPERTY* pProperties = XFA_GetElementProperties(eElement, iCount);
328  if (!pProperties || iCount < 1)
329    return nullptr;
330
331  auto it = std::find_if(pProperties, pProperties + iCount,
332                         [eProperty](const XFA_PROPERTY& prop) {
333                           return prop.eName == eProperty;
334                         });
335  if (it == pProperties + iCount)
336    return nullptr;
337
338  const XFA_ELEMENTINFO* pInfo = XFA_GetElementByID(eProperty);
339  ASSERT(pInfo);
340  if (dwPacket != XFA_XDPPACKET_UNKNOWN && !(dwPacket & pInfo->dwPackets))
341    return nullptr;
342  return it;
343}
344
345const XFA_PROPERTY* XFA_GetElementProperties(XFA_Element eElement,
346                                             int32_t& iCount) {
347  if (eElement == XFA_Element::Unknown)
348    return nullptr;
349
350  const XFA_ELEMENTHIERARCHY* pElement =
351      g_XFAElementPropertyIndex + static_cast<int32_t>(eElement);
352  iCount = pElement->wCount;
353  return g_XFAElementPropertyData + pElement->wStart;
354}
355
356const uint8_t* XFA_GetElementAttributes(XFA_Element eElement, int32_t& iCount) {
357  if (eElement == XFA_Element::Unknown)
358    return nullptr;
359
360  const XFA_ELEMENTHIERARCHY* pElement =
361      g_XFAElementAttributeIndex + static_cast<int32_t>(eElement);
362  iCount = pElement->wCount;
363  return g_XFAElementAttributeData + pElement->wStart;
364}
365
366const XFA_ELEMENTINFO* XFA_GetElementByID(XFA_Element eName) {
367  return eName != XFA_Element::Unknown
368             ? g_XFAElementData + static_cast<int32_t>(eName)
369             : nullptr;
370}
371
372XFA_Element XFA_GetElementTypeForName(const CFX_WideStringC& wsName) {
373  if (wsName.IsEmpty())
374    return XFA_Element::Unknown;
375
376  uint32_t uHash = FX_HashCode_GetW(wsName, false);
377  const XFA_ELEMENTINFO* pEnd = g_XFAElementData + g_iXFAElementCount;
378  auto pInfo = std::lower_bound(g_XFAElementData, pEnd, uHash,
379                                [](const XFA_ELEMENTINFO& info, uint32_t hash) {
380                                  return info.uHash < hash;
381                                });
382  if (pInfo < pEnd && pInfo->uHash == uHash)
383    return pInfo->eName;
384  return XFA_Element::Unknown;
385}
386
387CXFA_Measurement XFA_GetAttributeDefaultValue_Measure(XFA_Element eElement,
388                                                      XFA_ATTRIBUTE eAttribute,
389                                                      uint32_t dwPacket) {
390  void* pValue;
391  if (XFA_GetAttributeDefaultValue(pValue, eElement, eAttribute,
392                                   XFA_ATTRIBUTETYPE_Measure, dwPacket)) {
393    return *(CXFA_Measurement*)pValue;
394  }
395  return CXFA_Measurement();
396}
397
398bool XFA_GetAttributeDefaultValue(void*& pValue,
399                                  XFA_Element eElement,
400                                  XFA_ATTRIBUTE eAttribute,
401                                  XFA_ATTRIBUTETYPE eType,
402                                  uint32_t dwPacket) {
403  const XFA_ATTRIBUTEINFO* pInfo = XFA_GetAttributeByID(eAttribute);
404  if (!pInfo)
405    return false;
406  if (dwPacket && (dwPacket & pInfo->dwPackets) == 0)
407    return false;
408  if (pInfo->eType == eType) {
409    pValue = pInfo->pDefValue;
410    return true;
411  }
412  if (pInfo->eType == XFA_ATTRIBUTETYPE_NOTSURE) {
413    const XFA_NOTSUREATTRIBUTE* pAttr =
414        XFA_GetNotsureAttribute(eElement, eAttribute, eType);
415    if (pAttr) {
416      pValue = pAttr->pValue;
417      return true;
418    }
419  }
420  return false;
421}
422
423const XFA_ATTRIBUTEINFO* XFA_GetAttributeByName(const CFX_WideStringC& wsName) {
424  if (wsName.IsEmpty())
425    return nullptr;
426
427  uint32_t uHash = FX_HashCode_GetW(wsName, false);
428  int32_t iStart = 0;
429  int32_t iEnd = g_iXFAAttributeCount - 1;
430  do {
431    int32_t iMid = (iStart + iEnd) / 2;
432    const XFA_ATTRIBUTEINFO* pInfo = g_XFAAttributeData + iMid;
433    if (uHash == pInfo->uHash)
434      return pInfo;
435    if (uHash < pInfo->uHash)
436      iEnd = iMid - 1;
437    else
438      iStart = iMid + 1;
439  } while (iStart <= iEnd);
440  return nullptr;
441}
442
443const XFA_ATTRIBUTEINFO* XFA_GetAttributeByID(XFA_ATTRIBUTE eName) {
444  return (eName < g_iXFAAttributeCount) ? (g_XFAAttributeData + eName)
445                                        : nullptr;
446}
447
448const XFA_ATTRIBUTEENUMINFO* XFA_GetAttributeEnumByName(
449    const CFX_WideStringC& wsName) {
450  if (wsName.IsEmpty())
451    return nullptr;
452
453  uint32_t uHash = FX_HashCode_GetW(wsName, false);
454  int32_t iStart = 0;
455  int32_t iEnd = g_iXFAEnumCount - 1;
456  do {
457    int32_t iMid = (iStart + iEnd) / 2;
458    const XFA_ATTRIBUTEENUMINFO* pInfo = g_XFAEnumData + iMid;
459    if (uHash == pInfo->uHash)
460      return pInfo;
461    if (uHash < pInfo->uHash)
462      iEnd = iMid - 1;
463    else
464      iStart = iMid + 1;
465  } while (iStart <= iEnd);
466  return nullptr;
467}
468
469const XFA_PACKETINFO* XFA_GetPacketByIndex(XFA_PACKET ePacket) {
470  return g_XFAPacketData + ePacket;
471}
472
473const XFA_PACKETINFO* XFA_GetPacketByID(uint32_t dwPacket) {
474  int32_t iStart = 0, iEnd = g_iXFAPacketCount - 1;
475  do {
476    int32_t iMid = (iStart + iEnd) / 2;
477    uint32_t dwFind = (g_XFAPacketData + iMid)->eName;
478    if (dwPacket == dwFind)
479      return g_XFAPacketData + iMid;
480    if (dwPacket < dwFind)
481      iEnd = iMid - 1;
482    else
483      iStart = iMid + 1;
484  } while (iStart <= iEnd);
485  return nullptr;
486}
487