1// Copyright 2016 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 "core/fpdfdoc/cpdf_interform.h"
8
9#include <utility>
10#include <vector>
11
12#include "core/fpdfapi/font/cpdf_font.h"
13#include "core/fpdfapi/font/cpdf_fontencoding.h"
14#include "core/fpdfapi/page/cpdf_page.h"
15#include "core/fpdfapi/parser/cfdf_document.h"
16#include "core/fpdfapi/parser/cpdf_array.h"
17#include "core/fpdfapi/parser/cpdf_document.h"
18#include "core/fpdfapi/parser/cpdf_name.h"
19#include "core/fpdfapi/parser/cpdf_reference.h"
20#include "core/fpdfapi/parser/cpdf_string.h"
21#include "core/fpdfdoc/cpdf_filespec.h"
22#include "core/fpdfdoc/cpdf_formcontrol.h"
23#include "core/fxcrt/fx_codepage.h"
24#include "core/fxge/cfx_substfont.h"
25#include "core/fxge/fx_font.h"
26#include "third_party/base/ptr_util.h"
27#include "third_party/base/stl_util.h"
28
29namespace {
30
31const int nMaxRecursion = 32;
32
33const struct SupportFieldEncoding {
34  const char* m_name;
35  uint16_t m_codePage;
36} g_fieldEncoding[] = {
37    {"BigFive", 950},
38    {"GBK", 936},
39    {"Shift-JIS", 932},
40    {"UHC", 949},
41};
42
43WideString GetFieldValue(const CPDF_Dictionary& pFieldDict,
44                         const ByteString& bsEncoding) {
45  const ByteString csBValue = pFieldDict.GetStringFor("V");
46  for (const auto& encoding : g_fieldEncoding) {
47    if (bsEncoding == encoding.m_name)
48      return WideString::FromCodePage(csBValue.AsStringView(),
49                                      encoding.m_codePage);
50  }
51  ByteString csTemp = csBValue.Left(2);
52  if (csTemp == "\xFF\xFE" || csTemp == "\xFE\xFF")
53    return PDF_DecodeText(csBValue);
54  return WideString::FromLocal(csBValue.AsStringView());
55}
56
57void AddFont(CPDF_Dictionary*& pFormDict,
58             CPDF_Document* pDocument,
59             const CPDF_Font* pFont,
60             ByteString* csNameTag);
61
62void InitDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) {
63  if (!pDocument)
64    return;
65
66  if (!pFormDict) {
67    pFormDict = pDocument->NewIndirect<CPDF_Dictionary>();
68    pDocument->GetRoot()->SetNewFor<CPDF_Reference>("AcroForm", pDocument,
69                                                    pFormDict->GetObjNum());
70  }
71
72  ByteString csDA;
73  if (!pFormDict->KeyExist("DR")) {
74    ByteString csBaseName;
75    uint8_t charSet = CPDF_InterForm::GetNativeCharSet();
76    CPDF_Font* pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica");
77    if (pFont)
78      AddFont(pFormDict, pDocument, pFont, &csBaseName);
79
80    if (charSet != FX_CHARSET_ANSI) {
81      ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, nullptr);
82      if (!pFont || csFontName != "Helvetica") {
83        pFont = CPDF_InterForm::AddNativeFont(pDocument);
84        if (pFont) {
85          csBaseName.clear();
86          AddFont(pFormDict, pDocument, pFont, &csBaseName);
87        }
88      }
89    }
90    if (pFont)
91      csDA = "/" + PDF_NameEncode(csBaseName) + " 0 Tf";
92  }
93  if (!csDA.IsEmpty())
94    csDA += " ";
95
96  csDA += "0 g";
97  if (!pFormDict->KeyExist("DA"))
98    pFormDict->SetNewFor<CPDF_String>("DA", csDA, false);
99}
100
101CPDF_Font* GetFont(CPDF_Dictionary* pFormDict,
102                   CPDF_Document* pDocument,
103                   const ByteString& csNameTag) {
104  ByteString csAlias = PDF_NameDecode(csNameTag);
105  if (!pFormDict || csAlias.IsEmpty())
106    return nullptr;
107
108  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
109  if (!pDR)
110    return nullptr;
111
112  CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
113  if (!pFonts)
114    return nullptr;
115
116  CPDF_Dictionary* pElement = pFonts->GetDictFor(csAlias);
117  if (!pElement)
118    return nullptr;
119
120  if (pElement->GetStringFor("Type") == "Font")
121    return pDocument->LoadFont(pElement);
122  return nullptr;
123}
124
125CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
126                         CPDF_Document* pDocument,
127                         uint8_t charSet,
128                         ByteString* csNameTag) {
129  if (!pFormDict)
130    return nullptr;
131
132  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
133  if (!pDR)
134    return nullptr;
135
136  CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
137  if (!pFonts)
138    return nullptr;
139
140  for (const auto& it : *pFonts) {
141    const ByteString& csKey = it.first;
142    if (!it.second)
143      continue;
144
145    CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect());
146    if (!pElement)
147      continue;
148    if (pElement->GetStringFor("Type") != "Font")
149      continue;
150    CPDF_Font* pFind = pDocument->LoadFont(pElement);
151    if (!pFind)
152      continue;
153
154    CFX_SubstFont* pSubst = pFind->GetSubstFont();
155    if (!pSubst)
156      continue;
157
158    if (pSubst->m_Charset == static_cast<int>(charSet)) {
159      *csNameTag = csKey;
160      return pFind;
161    }
162  }
163  return nullptr;
164}
165
166bool FindFont(CPDF_Dictionary* pFormDict,
167              const CPDF_Font* pFont,
168              ByteString* csNameTag) {
169  if (!pFormDict || !pFont)
170    return false;
171
172  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
173  if (!pDR)
174    return false;
175
176  CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
177  if (!pFonts)
178    return false;
179
180  for (const auto& it : *pFonts) {
181    const ByteString& csKey = it.first;
182    if (!it.second)
183      continue;
184    CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect());
185    if (!pElement)
186      continue;
187    if (pElement->GetStringFor("Type") != "Font")
188      continue;
189    if (pFont->GetFontDict() == pElement) {
190      *csNameTag = csKey;
191      return true;
192    }
193  }
194  return false;
195}
196
197bool FindFont(CPDF_Dictionary* pFormDict,
198              CPDF_Document* pDocument,
199              ByteString csFontName,
200              CPDF_Font*& pFont,
201              ByteString* csNameTag) {
202  if (!pFormDict)
203    return false;
204
205  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
206  if (!pDR)
207    return false;
208
209  CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
210  if (!pFonts)
211    return false;
212
213  if (csFontName.GetLength() > 0)
214    csFontName.Remove(' ');
215
216  for (const auto& it : *pFonts) {
217    const ByteString& csKey = it.first;
218    if (!it.second)
219      continue;
220
221    CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect());
222    if (!pElement)
223      continue;
224    if (pElement->GetStringFor("Type") != "Font")
225      continue;
226    pFont = pDocument->LoadFont(pElement);
227    if (!pFont)
228      continue;
229
230    ByteString csBaseFont;
231    csBaseFont = pFont->GetBaseFont();
232    csBaseFont.Remove(' ');
233    if (csBaseFont == csFontName) {
234      *csNameTag = csKey;
235      return true;
236    }
237  }
238  return false;
239}
240
241void AddFont(CPDF_Dictionary*& pFormDict,
242             CPDF_Document* pDocument,
243             const CPDF_Font* pFont,
244             ByteString* csNameTag) {
245  if (!pFont)
246    return;
247  if (!pFormDict)
248    InitDict(pFormDict, pDocument);
249
250  ByteString csTag;
251  if (FindFont(pFormDict, pFont, &csTag)) {
252    *csNameTag = csTag;
253    return;
254  }
255  if (!pFormDict)
256    InitDict(pFormDict, pDocument);
257
258  CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
259  if (!pDR)
260    pDR = pFormDict->SetNewFor<CPDF_Dictionary>("DR");
261
262  CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
263  if (!pFonts)
264    pFonts = pDR->SetNewFor<CPDF_Dictionary>("Font");
265
266  if (csNameTag->IsEmpty())
267    *csNameTag = pFont->GetBaseFont();
268
269  csNameTag->Remove(' ');
270  *csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4,
271                                                       csNameTag->c_str());
272  pFonts->SetNewFor<CPDF_Reference>(*csNameTag, pDocument,
273                                    pFont->GetFontDict()->GetObjNum());
274}
275
276CPDF_Font* AddNativeFont(CPDF_Dictionary*& pFormDict,
277                         CPDF_Document* pDocument,
278                         uint8_t charSet,
279                         ByteString* csNameTag) {
280  if (!pFormDict)
281    InitDict(pFormDict, pDocument);
282
283  ByteString csTemp;
284  CPDF_Font* pFont = GetNativeFont(pFormDict, pDocument, charSet, &csTemp);
285  if (pFont) {
286    *csNameTag = csTemp;
287    return pFont;
288  }
289  ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, nullptr);
290  if (!csFontName.IsEmpty() &&
291      FindFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) {
292    return pFont;
293  }
294  pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument);
295  if (pFont)
296    AddFont(pFormDict, pDocument, pFont, csNameTag);
297
298  return pFont;
299}
300
301class CFieldNameExtractor {
302 public:
303  explicit CFieldNameExtractor(const WideString& full_name)
304      : m_FullName(full_name) {
305    m_pCur = m_FullName.c_str();
306    m_pEnd = m_pCur + m_FullName.GetLength();
307  }
308
309  void GetNext(const wchar_t*& pSubName, size_t& size) {
310    pSubName = m_pCur;
311    while (m_pCur < m_pEnd && m_pCur[0] != L'.')
312      m_pCur++;
313
314    size = static_cast<size_t>(m_pCur - pSubName);
315    if (m_pCur < m_pEnd && m_pCur[0] == L'.')
316      m_pCur++;
317  }
318
319 protected:
320  WideString m_FullName;
321  const wchar_t* m_pCur;
322  const wchar_t* m_pEnd;
323};
324
325#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
326typedef struct {
327  bool bFind;
328  LOGFONTA lf;
329} PDF_FONTDATA;
330
331static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe,
332                                      NEWTEXTMETRICEX* lpntme,
333                                      DWORD FontType,
334                                      LPARAM lParam) {
335  if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@'))
336    return 1;
337
338  PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam;
339  memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA));
340  pData->bFind = true;
341  return 0;
342}
343
344bool RetrieveSpecificFont(LOGFONTA& lf) {
345  PDF_FONTDATA fd;
346  memset(&fd, 0, sizeof(PDF_FONTDATA));
347  HDC hDC = ::GetDC(nullptr);
348  EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd,
349                      0);
350  ::ReleaseDC(nullptr, hDC);
351  if (fd.bFind)
352    memcpy(&lf, &fd.lf, sizeof(LOGFONTA));
353
354  return fd.bFind;
355}
356
357bool RetrieveSpecificFont(uint8_t charSet,
358                          uint8_t pitchAndFamily,
359                          LPCSTR pcsFontName,
360                          LOGFONTA& lf) {
361  memset(&lf, 0, sizeof(LOGFONTA));
362  lf.lfCharSet = charSet;
363  lf.lfPitchAndFamily = pitchAndFamily;
364  if (pcsFontName) {
365    // TODO(dsinclair): Should this be strncpy?
366    // NOLINTNEXTLINE(runtime/printf)
367    strcpy(lf.lfFaceName, pcsFontName);
368  }
369  return RetrieveSpecificFont(lf);
370}
371#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
372
373}  // namespace
374
375class CFieldTree {
376 public:
377  class Node {
378   public:
379    Node() : m_pField(nullptr), m_level(0) {}
380    Node(const WideString& short_name, int level)
381        : m_ShortName(short_name), m_level(level) {}
382    ~Node() {}
383
384    void AddChildNode(std::unique_ptr<Node> pNode) {
385      m_Children.push_back(std::move(pNode));
386    }
387
388    size_t GetChildrenCount() const { return m_Children.size(); }
389
390    Node* GetChildAt(size_t i) { return m_Children[i].get(); }
391    const Node* GetChildAt(size_t i) const { return m_Children[i].get(); }
392
393    CPDF_FormField* GetFieldAtIndex(size_t index) {
394      size_t nFieldsToGo = index;
395      return GetFieldInternal(&nFieldsToGo);
396    }
397
398    size_t CountFields() const { return CountFieldsInternal(); }
399
400    void SetField(std::unique_ptr<CPDF_FormField> pField) {
401      m_pField = std::move(pField);
402    }
403
404    CPDF_FormField* GetField() const { return m_pField.get(); }
405
406    const WideString& GetShortName() const { return m_ShortName; }
407
408    int GetLevel() const { return m_level; }
409
410   private:
411    CPDF_FormField* GetFieldInternal(size_t* pFieldsToGo) {
412      if (m_pField) {
413        if (*pFieldsToGo == 0)
414          return m_pField.get();
415
416        --*pFieldsToGo;
417      }
418      for (size_t i = 0; i < GetChildrenCount(); ++i) {
419        CPDF_FormField* pField = GetChildAt(i)->GetFieldInternal(pFieldsToGo);
420        if (pField)
421          return pField;
422      }
423      return nullptr;
424    }
425
426    size_t CountFieldsInternal() const {
427      size_t count = 0;
428      if (m_pField)
429        ++count;
430
431      for (size_t i = 0; i < GetChildrenCount(); ++i)
432        count += GetChildAt(i)->CountFieldsInternal();
433      return count;
434    }
435
436    std::vector<std::unique_ptr<Node>> m_Children;
437    WideString m_ShortName;
438    std::unique_ptr<CPDF_FormField> m_pField;
439    const int m_level;
440  };
441
442  CFieldTree();
443  ~CFieldTree();
444
445  bool SetField(const WideString& full_name,
446                std::unique_ptr<CPDF_FormField> pField);
447  CPDF_FormField* GetField(const WideString& full_name);
448
449  Node* FindNode(const WideString& full_name);
450  Node* AddChild(Node* pParent, const WideString& short_name);
451
452  Node* Lookup(Node* pParent, const WideString& short_name);
453
454  Node m_Root;
455};
456
457CFieldTree::CFieldTree() {}
458
459CFieldTree::~CFieldTree() {}
460
461CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
462                                       const WideString& short_name) {
463  if (!pParent)
464    return nullptr;
465
466  int level = pParent->GetLevel() + 1;
467  if (level > nMaxRecursion)
468    return nullptr;
469
470  auto pNew = pdfium::MakeUnique<Node>(short_name, pParent->GetLevel() + 1);
471  Node* pChild = pNew.get();
472  pParent->AddChildNode(std::move(pNew));
473  return pChild;
474}
475
476CFieldTree::Node* CFieldTree::Lookup(Node* pParent,
477                                     const WideString& short_name) {
478  if (!pParent)
479    return nullptr;
480
481  for (size_t i = 0; i < pParent->GetChildrenCount(); ++i) {
482    Node* pNode = pParent->GetChildAt(i);
483    if (pNode->GetShortName() == short_name)
484      return pNode;
485  }
486  return nullptr;
487}
488
489bool CFieldTree::SetField(const WideString& full_name,
490                          std::unique_ptr<CPDF_FormField> pField) {
491  if (full_name.IsEmpty())
492    return false;
493
494  CFieldNameExtractor name_extractor(full_name);
495  const wchar_t* pName;
496  size_t nLength;
497  name_extractor.GetNext(pName, nLength);
498  Node* pNode = &m_Root;
499  Node* pLast = nullptr;
500  while (nLength > 0) {
501    pLast = pNode;
502    WideString name = WideString(pName, nLength);
503    pNode = Lookup(pLast, name);
504    if (!pNode)
505      pNode = AddChild(pLast, name);
506    if (!pNode)
507      return false;
508
509    name_extractor.GetNext(pName, nLength);
510  }
511  if (pNode == &m_Root)
512    return false;
513
514  pNode->SetField(std::move(pField));
515  return true;
516}
517
518CPDF_FormField* CFieldTree::GetField(const WideString& full_name) {
519  if (full_name.IsEmpty())
520    return nullptr;
521
522  CFieldNameExtractor name_extractor(full_name);
523  const wchar_t* pName;
524  size_t nLength;
525  name_extractor.GetNext(pName, nLength);
526  Node* pNode = &m_Root;
527  Node* pLast = nullptr;
528  while (nLength > 0 && pNode) {
529    pLast = pNode;
530    WideString name = WideString(pName, nLength);
531    pNode = Lookup(pLast, name);
532    name_extractor.GetNext(pName, nLength);
533  }
534  return pNode ? pNode->GetField() : nullptr;
535}
536
537CFieldTree::Node* CFieldTree::FindNode(const WideString& full_name) {
538  if (full_name.IsEmpty())
539    return nullptr;
540
541  CFieldNameExtractor name_extractor(full_name);
542  const wchar_t* pName;
543  size_t nLength;
544  name_extractor.GetNext(pName, nLength);
545  Node* pNode = &m_Root;
546  Node* pLast = nullptr;
547  while (nLength > 0 && pNode) {
548    pLast = pNode;
549    WideString name = WideString(pName, nLength);
550    pNode = Lookup(pLast, name);
551    name_extractor.GetNext(pName, nLength);
552  }
553  return pNode;
554}
555
556CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict,
557                                  CPDF_Document* pDocument,
558                                  ByteString* csNameTag) {
559  uint8_t charSet = CPDF_InterForm::GetNativeCharSet();
560  return AddNativeFont(pFormDict, pDocument, charSet, csNameTag);
561}
562
563// static
564uint8_t CPDF_InterForm::GetNativeCharSet() {
565#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
566  uint8_t charSet = FX_CHARSET_ANSI;
567  UINT iCodePage = ::GetACP();
568  switch (iCodePage) {
569    case FX_CODEPAGE_ShiftJIS:
570      charSet = FX_CHARSET_ShiftJIS;
571      break;
572    case FX_CODEPAGE_ChineseSimplified:
573      charSet = FX_CHARSET_ChineseSimplified;
574      break;
575    case FX_CODEPAGE_ChineseTraditional:
576      charSet = FX_CHARSET_ChineseTraditional;
577      break;
578    case FX_CODEPAGE_MSWin_WesternEuropean:
579      charSet = FX_CHARSET_ANSI;
580      break;
581    case FX_CODEPAGE_MSDOS_Thai:
582      charSet = FX_CHARSET_Thai;
583      break;
584    case FX_CODEPAGE_Hangul:
585      charSet = FX_CHARSET_Hangul;
586      break;
587    case FX_CODEPAGE_UTF16LE:
588      charSet = FX_CHARSET_ANSI;
589      break;
590    case FX_CODEPAGE_MSWin_EasternEuropean:
591      charSet = FX_CHARSET_MSWin_EasternEuropean;
592      break;
593    case FX_CODEPAGE_MSWin_Cyrillic:
594      charSet = FX_CHARSET_MSWin_Cyrillic;
595      break;
596    case FX_CODEPAGE_MSWin_Greek:
597      charSet = FX_CHARSET_MSWin_Greek;
598      break;
599    case FX_CODEPAGE_MSWin_Turkish:
600      charSet = FX_CHARSET_MSWin_Turkish;
601      break;
602    case FX_CODEPAGE_MSWin_Hebrew:
603      charSet = FX_CHARSET_MSWin_Hebrew;
604      break;
605    case FX_CODEPAGE_MSWin_Arabic:
606      charSet = FX_CHARSET_MSWin_Arabic;
607      break;
608    case FX_CODEPAGE_MSWin_Baltic:
609      charSet = FX_CHARSET_MSWin_Baltic;
610      break;
611    case FX_CODEPAGE_MSWin_Vietnamese:
612      charSet = FX_CHARSET_MSWin_Vietnamese;
613      break;
614    case FX_CODEPAGE_Johab:
615      charSet = FX_CHARSET_Johab;
616      break;
617  }
618  return charSet;
619#else
620  return 0;
621#endif
622}
623
624CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument)
625    : m_pDocument(pDocument),
626      m_pFormDict(nullptr),
627      m_pFieldTree(pdfium::MakeUnique<CFieldTree>()),
628      m_pFormNotify(nullptr) {
629  CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
630  if (!pRoot)
631    return;
632
633  m_pFormDict = pRoot->GetDictFor("AcroForm");
634  if (!m_pFormDict)
635    return;
636
637  CPDF_Array* pFields = m_pFormDict->GetArrayFor("Fields");
638  if (!pFields)
639    return;
640
641  for (size_t i = 0; i < pFields->GetCount(); ++i)
642    LoadField(pFields->GetDictAt(i), 0);
643}
644
645CPDF_InterForm::~CPDF_InterForm() {}
646
647bool CPDF_InterForm::s_bUpdateAP = true;
648
649bool CPDF_InterForm::IsUpdateAPEnabled() {
650  return s_bUpdateAP;
651}
652
653void CPDF_InterForm::SetUpdateAP(bool bUpdateAP) {
654  s_bUpdateAP = bUpdateAP;
655}
656
657ByteString CPDF_InterForm::GenerateNewResourceName(
658    const CPDF_Dictionary* pResDict,
659    const char* csType,
660    int iMinLen,
661    const char* csPrefix) {
662  ByteString csStr = csPrefix;
663  ByteString csBType = csType;
664  if (csStr.IsEmpty()) {
665    if (csBType == "ExtGState")
666      csStr = "GS";
667    else if (csBType == "ColorSpace")
668      csStr = "CS";
669    else if (csBType == "Font")
670      csStr = "ZiTi";
671    else
672      csStr = "Res";
673  }
674  ByteString csTmp = csStr;
675  int iCount = csStr.GetLength();
676  int m = 0;
677  if (iMinLen > 0) {
678    csTmp.clear();
679    while (m < iMinLen && m < iCount)
680      csTmp += csStr[m++];
681    while (m < iMinLen) {
682      csTmp += '0' + m % 10;
683      m++;
684    }
685  } else {
686    m = iCount;
687  }
688  if (!pResDict)
689    return csTmp;
690
691  CPDF_Dictionary* pDict = pResDict->GetDictFor(csType);
692  if (!pDict)
693    return csTmp;
694
695  int num = 0;
696  ByteString bsNum;
697  while (true) {
698    ByteString csKey = csTmp + bsNum;
699    if (!pDict->KeyExist(csKey))
700      return csKey;
701    if (m < iCount)
702      csTmp += csStr[m++];
703    else
704      bsNum = ByteString::Format("%d", num++);
705
706    m++;
707  }
708  return csTmp;
709}
710
711CPDF_Font* CPDF_InterForm::AddStandardFont(CPDF_Document* pDocument,
712                                           ByteString csFontName) {
713  if (!pDocument || csFontName.IsEmpty())
714    return nullptr;
715
716  if (csFontName == "ZapfDingbats")
717    return pDocument->AddStandardFont(csFontName.c_str(), nullptr);
718
719  CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI);
720  return pDocument->AddStandardFont(csFontName.c_str(), &encoding);
721}
722
723ByteString CPDF_InterForm::GetNativeFont(uint8_t charSet, void* pLogFont) {
724  ByteString csFontName;
725#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
726  LOGFONTA lf = {};
727  if (charSet == FX_CHARSET_ANSI) {
728    csFontName = "Helvetica";
729    return csFontName;
730  }
731  bool bRet = false;
732  if (charSet == FX_CHARSET_ShiftJIS) {
733    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
734                                "MS Mincho", lf);
735  } else if (charSet == FX_CHARSET_ChineseSimplified) {
736    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun",
737                                lf);
738  } else if (charSet == FX_CHARSET_ChineseTraditional) {
739    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MingLiU",
740                                lf);
741  }
742  if (!bRet) {
743    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
744                                "Arial Unicode MS", lf);
745  }
746  if (!bRet) {
747    bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
748                                "Microsoft Sans Serif", lf);
749  }
750  if (!bRet) {
751    bRet =
752        RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, nullptr, lf);
753  }
754  if (bRet) {
755    if (pLogFont)
756      memcpy(pLogFont, &lf, sizeof(LOGFONTA));
757
758    csFontName = lf.lfFaceName;
759    return csFontName;
760  }
761#endif
762  return csFontName;
763}
764
765CPDF_Font* CPDF_InterForm::AddNativeFont(uint8_t charSet,
766                                         CPDF_Document* pDocument) {
767  if (!pDocument)
768    return nullptr;
769
770#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
771  LOGFONTA lf;
772  ByteString csFontName = GetNativeFont(charSet, &lf);
773  if (!csFontName.IsEmpty()) {
774    if (csFontName == "Helvetica")
775      return AddStandardFont(pDocument, csFontName);
776    return pDocument->AddWindowsFont(&lf, false, true);
777  }
778#endif
779  return nullptr;
780}
781
782CPDF_Font* CPDF_InterForm::AddNativeFont(CPDF_Document* pDocument) {
783  return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr;
784}
785
786size_t CPDF_InterForm::CountFields(const WideString& csFieldName) const {
787  if (csFieldName.IsEmpty())
788    return m_pFieldTree->m_Root.CountFields();
789
790  CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
791  return pNode ? pNode->CountFields() : 0;
792}
793
794CPDF_FormField* CPDF_InterForm::GetField(uint32_t index,
795                                         const WideString& csFieldName) const {
796  if (csFieldName.IsEmpty())
797    return m_pFieldTree->m_Root.GetFieldAtIndex(index);
798
799  CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
800  return pNode ? pNode->GetFieldAtIndex(index) : nullptr;
801}
802
803CPDF_FormField* CPDF_InterForm::GetFieldByDict(
804    CPDF_Dictionary* pFieldDict) const {
805  if (!pFieldDict)
806    return nullptr;
807
808  WideString csWName = FPDF_GetFullName(pFieldDict);
809  return m_pFieldTree->GetField(csWName);
810}
811
812CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage,
813                                                    const CFX_PointF& point,
814
815                                                    int* z_order) const {
816  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
817  if (!pAnnotList)
818    return nullptr;
819
820  for (size_t i = pAnnotList->GetCount(); i > 0; --i) {
821    size_t annot_index = i - 1;
822    CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index);
823    if (!pAnnot)
824      continue;
825
826    const auto it = m_ControlMap.find(pAnnot);
827    if (it == m_ControlMap.end())
828      continue;
829
830    CPDF_FormControl* pControl = it->second.get();
831    if (!pControl->GetRect().Contains(point))
832      continue;
833
834    if (z_order)
835      *z_order = static_cast<int>(annot_index);
836    return pControl;
837  }
838  return nullptr;
839}
840
841CPDF_FormControl* CPDF_InterForm::GetControlByDict(
842    const CPDF_Dictionary* pWidgetDict) const {
843  const auto it = m_ControlMap.find(pWidgetDict);
844  return it != m_ControlMap.end() ? it->second.get() : nullptr;
845}
846
847bool CPDF_InterForm::NeedConstructAP() const {
848  return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances");
849}
850
851int CPDF_InterForm::CountFieldsInCalculationOrder() {
852  if (!m_pFormDict)
853    return 0;
854
855  CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
856  return pArray ? pArray->GetCount() : 0;
857}
858
859CPDF_FormField* CPDF_InterForm::GetFieldInCalculationOrder(int index) {
860  if (!m_pFormDict || index < 0)
861    return nullptr;
862
863  CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
864  if (!pArray)
865    return nullptr;
866
867  CPDF_Dictionary* pElement = ToDictionary(pArray->GetDirectObjectAt(index));
868  return pElement ? GetFieldByDict(pElement) : nullptr;
869}
870
871int CPDF_InterForm::FindFieldInCalculationOrder(const CPDF_FormField* pField) {
872  if (!m_pFormDict || !pField)
873    return -1;
874
875  CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
876  if (!pArray)
877    return -1;
878
879  for (size_t i = 0; i < pArray->GetCount(); i++) {
880    CPDF_Object* pElement = pArray->GetDirectObjectAt(i);
881    if (pElement == pField->GetDict())
882      return i;
883  }
884  return -1;
885}
886
887CPDF_Font* CPDF_InterForm::GetFormFont(ByteString csNameTag) const {
888  return GetFont(m_pFormDict.Get(), m_pDocument.Get(), csNameTag);
889}
890
891CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() const {
892  if (!m_pFormDict)
893    return CPDF_DefaultAppearance();
894  return CPDF_DefaultAppearance(m_pFormDict->GetStringFor("DA"));
895}
896
897int CPDF_InterForm::GetFormAlignment() const {
898  return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0;
899}
900
901bool CPDF_InterForm::ResetForm(const std::vector<CPDF_FormField*>& fields,
902                               bool bIncludeOrExclude,
903                               bool bNotify) {
904  if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
905    return false;
906
907  size_t nCount = m_pFieldTree->m_Root.CountFields();
908  for (size_t i = 0; i < nCount; ++i) {
909    CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
910    if (!pField)
911      continue;
912
913    if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField))
914      pField->ResetField(bNotify);
915  }
916  if (bNotify && m_pFormNotify)
917    m_pFormNotify->AfterFormReset(this);
918  return true;
919}
920
921bool CPDF_InterForm::ResetForm(bool bNotify) {
922  if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
923    return false;
924
925  size_t nCount = m_pFieldTree->m_Root.CountFields();
926  for (size_t i = 0; i < nCount; ++i) {
927    CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
928    if (!pField)
929      continue;
930
931    pField->ResetField(bNotify);
932  }
933  if (bNotify && m_pFormNotify)
934    m_pFormNotify->AfterFormReset(this);
935  return true;
936}
937
938void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) {
939  if (nLevel > nMaxRecursion)
940    return;
941  if (!pFieldDict)
942    return;
943
944  uint32_t dwParentObjNum = pFieldDict->GetObjNum();
945  CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
946  if (!pKids) {
947    AddTerminalField(pFieldDict);
948    return;
949  }
950
951  CPDF_Dictionary* pFirstKid = pKids->GetDictAt(0);
952  if (!pFirstKid)
953    return;
954
955  if (pFirstKid->KeyExist("T") || pFirstKid->KeyExist("Kids")) {
956    for (size_t i = 0; i < pKids->GetCount(); i++) {
957      CPDF_Dictionary* pChildDict = pKids->GetDictAt(i);
958      if (pChildDict) {
959        if (pChildDict->GetObjNum() != dwParentObjNum)
960          LoadField(pChildDict, nLevel + 1);
961      }
962    }
963  } else {
964    AddTerminalField(pFieldDict);
965  }
966}
967
968bool CPDF_InterForm::HasXFAForm() const {
969  return m_pFormDict && m_pFormDict->GetArrayFor("XFA");
970}
971
972void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) {
973  CPDF_Dictionary* pPageDict = pPage->m_pFormDict.Get();
974  if (!pPageDict)
975    return;
976
977  CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots");
978  if (!pAnnots)
979    return;
980
981  for (size_t i = 0; i < pAnnots->GetCount(); i++) {
982    CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i);
983    if (pAnnot && pAnnot->GetStringFor("Subtype") == "Widget")
984      LoadField(pAnnot, 0);
985  }
986}
987
988void CPDF_InterForm::AddTerminalField(CPDF_Dictionary* pFieldDict) {
989  if (!pFieldDict->KeyExist("FT")) {
990    // Key "FT" is required for terminal fields, it is also inheritable.
991    CPDF_Dictionary* pParentDict = pFieldDict->GetDictFor("Parent");
992    if (!pParentDict || !pParentDict->KeyExist("FT"))
993      return;
994  }
995
996  CPDF_Dictionary* pDict = pFieldDict;
997  WideString csWName = FPDF_GetFullName(pFieldDict);
998  if (csWName.IsEmpty())
999    return;
1000
1001  CPDF_FormField* pField = nullptr;
1002  pField = m_pFieldTree->GetField(csWName);
1003  if (!pField) {
1004    CPDF_Dictionary* pParent = pFieldDict;
1005    if (!pFieldDict->KeyExist("T") &&
1006        pFieldDict->GetStringFor("Subtype") == "Widget") {
1007      pParent = pFieldDict->GetDictFor("Parent");
1008      if (!pParent)
1009        pParent = pFieldDict;
1010    }
1011
1012    if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) {
1013      if (pFieldDict->KeyExist("FT")) {
1014        CPDF_Object* pFTValue = pFieldDict->GetDirectObjectFor("FT");
1015        if (pFTValue)
1016          pParent->SetFor("FT", pFTValue->Clone());
1017      }
1018
1019      if (pFieldDict->KeyExist("Ff")) {
1020        CPDF_Object* pFfValue = pFieldDict->GetDirectObjectFor("Ff");
1021        if (pFfValue)
1022          pParent->SetFor("Ff", pFfValue->Clone());
1023      }
1024    }
1025
1026    auto newField = pdfium::MakeUnique<CPDF_FormField>(this, pParent);
1027    pField = newField.get();
1028    CPDF_Object* pTObj = pDict->GetObjectFor("T");
1029    if (ToReference(pTObj)) {
1030      std::unique_ptr<CPDF_Object> pClone = pTObj->CloneDirectObject();
1031      if (pClone)
1032        pDict->SetFor("T", std::move(pClone));
1033      else
1034        pDict->SetNewFor<CPDF_Name>("T", "");
1035    }
1036    if (!m_pFieldTree->SetField(csWName, std::move(newField)))
1037      return;
1038  }
1039
1040  CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
1041  if (pKids) {
1042    for (size_t i = 0; i < pKids->GetCount(); i++) {
1043      CPDF_Dictionary* pKid = pKids->GetDictAt(i);
1044      if (!pKid)
1045        continue;
1046      if (pKid->GetStringFor("Subtype") != "Widget")
1047        continue;
1048
1049      AddControl(pField, pKid);
1050    }
1051  } else {
1052    if (pFieldDict->GetStringFor("Subtype") == "Widget")
1053      AddControl(pField, pFieldDict);
1054  }
1055}
1056
1057CPDF_FormControl* CPDF_InterForm::AddControl(CPDF_FormField* pField,
1058                                             CPDF_Dictionary* pWidgetDict) {
1059  const auto it = m_ControlMap.find(pWidgetDict);
1060  if (it != m_ControlMap.end())
1061    return it->second.get();
1062
1063  auto pNew = pdfium::MakeUnique<CPDF_FormControl>(pField, pWidgetDict);
1064  CPDF_FormControl* pControl = pNew.get();
1065  m_ControlMap[pWidgetDict] = std::move(pNew);
1066  pField->AddFormControl(pControl);
1067  return pControl;
1068}
1069
1070bool CPDF_InterForm::CheckRequiredFields(
1071    const std::vector<CPDF_FormField*>* fields,
1072    bool bIncludeOrExclude) const {
1073  size_t nCount = m_pFieldTree->m_Root.CountFields();
1074  for (size_t i = 0; i < nCount; ++i) {
1075    CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
1076    if (!pField)
1077      continue;
1078
1079    int32_t iType = pField->GetType();
1080    if (iType == CPDF_FormField::PushButton ||
1081        iType == CPDF_FormField::CheckBox || iType == CPDF_FormField::ListBox) {
1082      continue;
1083    }
1084    uint32_t dwFlags = pField->GetFieldFlags();
1085    // TODO(thestig): Look up these magic numbers and add constants for them.
1086    if (dwFlags & FORMFLAG_NOEXPORT)
1087      continue;
1088
1089    bool bFind = true;
1090    if (fields)
1091      bFind = pdfium::ContainsValue(*fields, pField);
1092    if (bIncludeOrExclude == bFind) {
1093      const CPDF_Dictionary* pFieldDict = pField->GetDict();
1094      if ((dwFlags & FORMFLAG_REQUIRED) != 0 &&
1095          pFieldDict->GetStringFor("V").IsEmpty()) {
1096        return false;
1097      }
1098    }
1099  }
1100  return true;
1101}
1102
1103std::unique_ptr<CFDF_Document> CPDF_InterForm::ExportToFDF(
1104    const WideString& pdf_path,
1105    bool bSimpleFileSpec) const {
1106  std::vector<CPDF_FormField*> fields;
1107  size_t nCount = m_pFieldTree->m_Root.CountFields();
1108  for (size_t i = 0; i < nCount; ++i)
1109    fields.push_back(m_pFieldTree->m_Root.GetFieldAtIndex(i));
1110  return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec);
1111}
1112
1113std::unique_ptr<CFDF_Document> CPDF_InterForm::ExportToFDF(
1114    const WideString& pdf_path,
1115    const std::vector<CPDF_FormField*>& fields,
1116    bool bIncludeOrExclude,
1117    bool bSimpleFileSpec) const {
1118  std::unique_ptr<CFDF_Document> pDoc = CFDF_Document::CreateNewDoc();
1119  if (!pDoc)
1120    return nullptr;
1121
1122  CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDictFor("FDF");
1123  if (!pdf_path.IsEmpty()) {
1124    if (bSimpleFileSpec) {
1125      WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path);
1126      pMainDict->SetNewFor<CPDF_String>(
1127          "F", ByteString::FromUnicode(wsFilePath), false);
1128      pMainDict->SetNewFor<CPDF_String>("UF", PDF_EncodeText(wsFilePath),
1129                                        false);
1130    } else {
1131      auto pNewDict =
1132          pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
1133      pNewDict->SetNewFor<CPDF_Name>("Type", "Filespec");
1134      CPDF_FileSpec filespec(pNewDict.get());
1135      filespec.SetFileName(pdf_path);
1136      pMainDict->SetFor("F", std::move(pNewDict));
1137    }
1138  }
1139
1140  CPDF_Array* pFields = pMainDict->SetNewFor<CPDF_Array>("Fields");
1141  size_t nCount = m_pFieldTree->m_Root.CountFields();
1142  for (size_t i = 0; i < nCount; ++i) {
1143    CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
1144    if (!pField || pField->GetType() == CPDF_FormField::PushButton)
1145      continue;
1146
1147    uint32_t dwFlags = pField->GetFieldFlags();
1148    if (dwFlags & 0x04)
1149      continue;
1150
1151    if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) {
1152      if ((dwFlags & 0x02) != 0 &&
1153          pField->GetDict()->GetStringFor("V").IsEmpty()) {
1154        continue;
1155      }
1156
1157      WideString fullname = FPDF_GetFullName(pField->GetFieldDict());
1158      auto pFieldDict =
1159          pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool());
1160      pFieldDict->SetNewFor<CPDF_String>("T", fullname);
1161      if (pField->GetType() == CPDF_FormField::CheckBox ||
1162          pField->GetType() == CPDF_FormField::RadioButton) {
1163        WideString csExport = pField->GetCheckValue(false);
1164        ByteString csBExport = PDF_EncodeText(csExport);
1165        CPDF_Object* pOpt = FPDF_GetFieldAttr(pField->GetDict(), "Opt");
1166        if (pOpt)
1167          pFieldDict->SetNewFor<CPDF_String>("V", csBExport, false);
1168        else
1169          pFieldDict->SetNewFor<CPDF_Name>("V", csBExport);
1170      } else {
1171        CPDF_Object* pV = FPDF_GetFieldAttr(pField->GetDict(), "V");
1172        if (pV)
1173          pFieldDict->SetFor("V", pV->CloneDirectObject());
1174      }
1175      pFields->Add(std::move(pFieldDict));
1176    }
1177  }
1178  return pDoc;
1179}
1180
1181void CPDF_InterForm::FDF_ImportField(CPDF_Dictionary* pFieldDict,
1182                                     const WideString& parent_name,
1183                                     bool bNotify,
1184                                     int nLevel) {
1185  WideString name;
1186  if (!parent_name.IsEmpty())
1187    name = parent_name + L".";
1188
1189  name += pFieldDict->GetUnicodeTextFor("T");
1190  CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
1191  if (pKids) {
1192    for (size_t i = 0; i < pKids->GetCount(); i++) {
1193      CPDF_Dictionary* pKid = pKids->GetDictAt(i);
1194      if (!pKid)
1195        continue;
1196      if (nLevel <= nMaxRecursion)
1197        FDF_ImportField(pKid, name, bNotify, nLevel + 1);
1198    }
1199    return;
1200  }
1201  if (!pFieldDict->KeyExist("V"))
1202    return;
1203
1204  CPDF_FormField* pField = m_pFieldTree->GetField(name);
1205  if (!pField)
1206    return;
1207
1208  WideString csWValue = GetFieldValue(*pFieldDict, m_bsEncoding);
1209  FormFieldType fieldType = pField->GetFieldType();
1210  if (bNotify && m_pFormNotify) {
1211    if (fieldType == FormFieldType::kListBox) {
1212      if (m_pFormNotify->BeforeSelectionChange(pField, csWValue) < 0)
1213        return;
1214    } else if (fieldType == FormFieldType::kComboBox ||
1215               fieldType == FormFieldType::kTextField) {
1216      if (m_pFormNotify->BeforeValueChange(pField, csWValue) < 0)
1217        return;
1218    }
1219  }
1220  pField->SetValue(csWValue);
1221  CPDF_FormField::Type eType = pField->GetType();
1222  if ((eType == CPDF_FormField::ListBox || eType == CPDF_FormField::ComboBox) &&
1223      pFieldDict->KeyExist("Opt")) {
1224    pField->SetOpt(pFieldDict->GetDirectObjectFor("Opt")->CloneDirectObject());
1225  }
1226
1227  if (bNotify && m_pFormNotify) {
1228    if (fieldType == FormFieldType::kCheckBox ||
1229        fieldType == FormFieldType::kRadioButton) {
1230      m_pFormNotify->AfterCheckedStatusChange(pField);
1231    } else if (fieldType == FormFieldType::kListBox) {
1232      m_pFormNotify->AfterSelectionChange(pField);
1233    } else if (fieldType == FormFieldType::kComboBox ||
1234               fieldType == FormFieldType::kTextField) {
1235      m_pFormNotify->AfterValueChange(pField);
1236    }
1237  }
1238}
1239
1240void CPDF_InterForm::SetFormNotify(IPDF_FormNotify* pNotify) {
1241  m_pFormNotify = pNotify;
1242}
1243