// Copyright 2016 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfdoc/cpdf_interform.h" #include <utility> #include <vector> #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cfdf_document.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfdoc/cpdf_filespec.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxge/cfx_substfont.h" #include "core/fxge/fx_font.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" namespace { const int nMaxRecursion = 32; const struct SupportFieldEncoding { const char* m_name; uint16_t m_codePage; } g_fieldEncoding[] = { {"BigFive", 950}, {"GBK", 936}, {"Shift-JIS", 932}, {"UHC", 949}, }; WideString GetFieldValue(const CPDF_Dictionary& pFieldDict, const ByteString& bsEncoding) { const ByteString csBValue = pFieldDict.GetStringFor("V"); for (const auto& encoding : g_fieldEncoding) { if (bsEncoding == encoding.m_name) return WideString::FromCodePage(csBValue.AsStringView(), encoding.m_codePage); } ByteString csTemp = csBValue.Left(2); if (csTemp == "\xFF\xFE" || csTemp == "\xFE\xFF") return PDF_DecodeText(csBValue); return WideString::FromLocal(csBValue.AsStringView()); } void AddFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, const CPDF_Font* pFont, ByteString* csNameTag); void InitDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) { if (!pDocument) return; if (!pFormDict) { pFormDict = pDocument->NewIndirect<CPDF_Dictionary>(); pDocument->GetRoot()->SetNewFor<CPDF_Reference>("AcroForm", pDocument, pFormDict->GetObjNum()); } ByteString csDA; if (!pFormDict->KeyExist("DR")) { ByteString csBaseName; uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); CPDF_Font* pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica"); if (pFont) AddFont(pFormDict, pDocument, pFont, &csBaseName); if (charSet != FX_CHARSET_ANSI) { ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, nullptr); if (!pFont || csFontName != "Helvetica") { pFont = CPDF_InterForm::AddNativeFont(pDocument); if (pFont) { csBaseName.clear(); AddFont(pFormDict, pDocument, pFont, &csBaseName); } } } if (pFont) csDA = "/" + PDF_NameEncode(csBaseName) + " 0 Tf"; } if (!csDA.IsEmpty()) csDA += " "; csDA += "0 g"; if (!pFormDict->KeyExist("DA")) pFormDict->SetNewFor<CPDF_String>("DA", csDA, false); } CPDF_Font* GetFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, const ByteString& csNameTag) { ByteString csAlias = PDF_NameDecode(csNameTag); if (!pFormDict || csAlias.IsEmpty()) return nullptr; CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); if (!pDR) return nullptr; CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); if (!pFonts) return nullptr; CPDF_Dictionary* pElement = pFonts->GetDictFor(csAlias); if (!pElement) return nullptr; if (pElement->GetStringFor("Type") == "Font") return pDocument->LoadFont(pElement); return nullptr; } CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, uint8_t charSet, ByteString* csNameTag) { if (!pFormDict) return nullptr; CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); if (!pDR) return nullptr; CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); if (!pFonts) return nullptr; for (const auto& it : *pFonts) { const ByteString& csKey = it.first; if (!it.second) continue; CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); if (!pElement) continue; if (pElement->GetStringFor("Type") != "Font") continue; CPDF_Font* pFind = pDocument->LoadFont(pElement); if (!pFind) continue; CFX_SubstFont* pSubst = pFind->GetSubstFont(); if (!pSubst) continue; if (pSubst->m_Charset == static_cast<int>(charSet)) { *csNameTag = csKey; return pFind; } } return nullptr; } bool FindFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont, ByteString* csNameTag) { if (!pFormDict || !pFont) return false; CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); if (!pDR) return false; CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); if (!pFonts) return false; for (const auto& it : *pFonts) { const ByteString& csKey = it.first; if (!it.second) continue; CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); if (!pElement) continue; if (pElement->GetStringFor("Type") != "Font") continue; if (pFont->GetFontDict() == pElement) { *csNameTag = csKey; return true; } } return false; } bool FindFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, ByteString csFontName, CPDF_Font*& pFont, ByteString* csNameTag) { if (!pFormDict) return false; CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); if (!pDR) return false; CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); if (!pFonts) return false; if (csFontName.GetLength() > 0) csFontName.Remove(' '); for (const auto& it : *pFonts) { const ByteString& csKey = it.first; if (!it.second) continue; CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); if (!pElement) continue; if (pElement->GetStringFor("Type") != "Font") continue; pFont = pDocument->LoadFont(pElement); if (!pFont) continue; ByteString csBaseFont; csBaseFont = pFont->GetBaseFont(); csBaseFont.Remove(' '); if (csBaseFont == csFontName) { *csNameTag = csKey; return true; } } return false; } void AddFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, const CPDF_Font* pFont, ByteString* csNameTag) { if (!pFont) return; if (!pFormDict) InitDict(pFormDict, pDocument); ByteString csTag; if (FindFont(pFormDict, pFont, &csTag)) { *csNameTag = csTag; return; } if (!pFormDict) InitDict(pFormDict, pDocument); CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); if (!pDR) pDR = pFormDict->SetNewFor<CPDF_Dictionary>("DR"); CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); if (!pFonts) pFonts = pDR->SetNewFor<CPDF_Dictionary>("Font"); if (csNameTag->IsEmpty()) *csNameTag = pFont->GetBaseFont(); csNameTag->Remove(' '); *csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4, csNameTag->c_str()); pFonts->SetNewFor<CPDF_Reference>(*csNameTag, pDocument, pFont->GetFontDict()->GetObjNum()); } CPDF_Font* AddNativeFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, uint8_t charSet, ByteString* csNameTag) { if (!pFormDict) InitDict(pFormDict, pDocument); ByteString csTemp; CPDF_Font* pFont = GetNativeFont(pFormDict, pDocument, charSet, &csTemp); if (pFont) { *csNameTag = csTemp; return pFont; } ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, nullptr); if (!csFontName.IsEmpty() && FindFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) { return pFont; } pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument); if (pFont) AddFont(pFormDict, pDocument, pFont, csNameTag); return pFont; } class CFieldNameExtractor { public: explicit CFieldNameExtractor(const WideString& full_name) : m_FullName(full_name) { m_pCur = m_FullName.c_str(); m_pEnd = m_pCur + m_FullName.GetLength(); } void GetNext(const wchar_t*& pSubName, size_t& size) { pSubName = m_pCur; while (m_pCur < m_pEnd && m_pCur[0] != L'.') m_pCur++; size = static_cast<size_t>(m_pCur - pSubName); if (m_pCur < m_pEnd && m_pCur[0] == L'.') m_pCur++; } protected: WideString m_FullName; const wchar_t* m_pCur; const wchar_t* m_pEnd; }; #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ typedef struct { bool bFind; LOGFONTA lf; } PDF_FONTDATA; static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe, NEWTEXTMETRICEX* lpntme, DWORD FontType, LPARAM lParam) { if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) return 1; PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam; memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)); pData->bFind = true; return 0; } bool RetrieveSpecificFont(LOGFONTA& lf) { PDF_FONTDATA fd; memset(&fd, 0, sizeof(PDF_FONTDATA)); HDC hDC = ::GetDC(nullptr); EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd, 0); ::ReleaseDC(nullptr, hDC); if (fd.bFind) memcpy(&lf, &fd.lf, sizeof(LOGFONTA)); return fd.bFind; } bool RetrieveSpecificFont(uint8_t charSet, uint8_t pitchAndFamily, LPCSTR pcsFontName, LOGFONTA& lf) { memset(&lf, 0, sizeof(LOGFONTA)); lf.lfCharSet = charSet; lf.lfPitchAndFamily = pitchAndFamily; if (pcsFontName) { // TODO(dsinclair): Should this be strncpy? // NOLINTNEXTLINE(runtime/printf) strcpy(lf.lfFaceName, pcsFontName); } return RetrieveSpecificFont(lf); } #endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ int CompareFieldName(const WideString& name1, const WideString& name2) { const wchar_t* ptr1 = name1.c_str(); const wchar_t* ptr2 = name2.c_str(); if (name1.GetLength() == name2.GetLength()) return name1 == name2 ? 1 : 0; size_t i = 0; while (ptr1[i] == ptr2[i]) i++; if (i == name1.GetLength()) return 2; if (i == name2.GetLength()) return 3; return 0; } } // namespace class CFieldTree { public: class Node { public: Node() : m_pField(nullptr), m_level(0) {} Node(const WideString& short_name, int level) : m_ShortName(short_name), m_level(level) {} ~Node() {} void AddChildNode(std::unique_ptr<Node> pNode) { m_Children.push_back(std::move(pNode)); } size_t GetChildrenCount() const { return m_Children.size(); } Node* GetChildAt(size_t i) { return m_Children[i].get(); } const Node* GetChildAt(size_t i) const { return m_Children[i].get(); } CPDF_FormField* GetFieldAtIndex(size_t index) { size_t nFieldsToGo = index; return GetFieldInternal(&nFieldsToGo); } size_t CountFields() const { return CountFieldsInternal(); } void SetField(std::unique_ptr<CPDF_FormField> pField) { m_pField = std::move(pField); } CPDF_FormField* GetField() const { return m_pField.get(); } const WideString& GetShortName() const { return m_ShortName; } int GetLevel() const { return m_level; } private: CPDF_FormField* GetFieldInternal(size_t* pFieldsToGo) { if (m_pField) { if (*pFieldsToGo == 0) return m_pField.get(); --*pFieldsToGo; } for (size_t i = 0; i < GetChildrenCount(); ++i) { CPDF_FormField* pField = GetChildAt(i)->GetFieldInternal(pFieldsToGo); if (pField) return pField; } return nullptr; } size_t CountFieldsInternal() const { size_t count = 0; if (m_pField) ++count; for (size_t i = 0; i < GetChildrenCount(); ++i) count += GetChildAt(i)->CountFieldsInternal(); return count; } std::vector<std::unique_ptr<Node>> m_Children; WideString m_ShortName; std::unique_ptr<CPDF_FormField> m_pField; const int m_level; }; CFieldTree(); ~CFieldTree(); bool SetField(const WideString& full_name, std::unique_ptr<CPDF_FormField> pField); CPDF_FormField* GetField(const WideString& full_name); Node* FindNode(const WideString& full_name); Node* AddChild(Node* pParent, const WideString& short_name); Node* Lookup(Node* pParent, const WideString& short_name); Node m_Root; }; CFieldTree::CFieldTree() {} CFieldTree::~CFieldTree() {} CFieldTree::Node* CFieldTree::AddChild(Node* pParent, const WideString& short_name) { if (!pParent) return nullptr; int level = pParent->GetLevel() + 1; if (level > nMaxRecursion) return nullptr; auto pNew = pdfium::MakeUnique<Node>(short_name, pParent->GetLevel() + 1); Node* pChild = pNew.get(); pParent->AddChildNode(std::move(pNew)); return pChild; } CFieldTree::Node* CFieldTree::Lookup(Node* pParent, const WideString& short_name) { if (!pParent) return nullptr; for (size_t i = 0; i < pParent->GetChildrenCount(); ++i) { Node* pNode = pParent->GetChildAt(i); if (pNode->GetShortName() == short_name) return pNode; } return nullptr; } bool CFieldTree::SetField(const WideString& full_name, std::unique_ptr<CPDF_FormField> pField) { if (full_name.IsEmpty()) return false; CFieldNameExtractor name_extractor(full_name); const wchar_t* pName; size_t nLength; name_extractor.GetNext(pName, nLength); Node* pNode = &m_Root; Node* pLast = nullptr; while (nLength > 0) { pLast = pNode; WideString name = WideString(pName, nLength); pNode = Lookup(pLast, name); if (!pNode) pNode = AddChild(pLast, name); if (!pNode) return false; name_extractor.GetNext(pName, nLength); } if (pNode == &m_Root) return false; pNode->SetField(std::move(pField)); return true; } CPDF_FormField* CFieldTree::GetField(const WideString& full_name) { if (full_name.IsEmpty()) return nullptr; CFieldNameExtractor name_extractor(full_name); const wchar_t* pName; size_t nLength; name_extractor.GetNext(pName, nLength); Node* pNode = &m_Root; Node* pLast = nullptr; while (nLength > 0 && pNode) { pLast = pNode; WideString name = WideString(pName, nLength); pNode = Lookup(pLast, name); name_extractor.GetNext(pName, nLength); } return pNode ? pNode->GetField() : nullptr; } CFieldTree::Node* CFieldTree::FindNode(const WideString& full_name) { if (full_name.IsEmpty()) return nullptr; CFieldNameExtractor name_extractor(full_name); const wchar_t* pName; size_t nLength; name_extractor.GetNext(pName, nLength); Node* pNode = &m_Root; Node* pLast = nullptr; while (nLength > 0 && pNode) { pLast = pNode; WideString name = WideString(pName, nLength); pNode = Lookup(pLast, name); name_extractor.GetNext(pName, nLength); } return pNode; } CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, ByteString* csNameTag) { uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); return AddNativeFont(pFormDict, pDocument, charSet, csNameTag); } // static uint8_t CPDF_InterForm::GetNativeCharSet() { #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ uint8_t charSet = FX_CHARSET_ANSI; UINT iCodePage = ::GetACP(); switch (iCodePage) { case FX_CODEPAGE_ShiftJIS: charSet = FX_CHARSET_ShiftJIS; break; case FX_CODEPAGE_ChineseSimplified: charSet = FX_CHARSET_ChineseSimplified; break; case FX_CODEPAGE_ChineseTraditional: charSet = FX_CHARSET_ChineseTraditional; break; case FX_CODEPAGE_MSWin_WesternEuropean: charSet = FX_CHARSET_ANSI; break; case FX_CODEPAGE_MSDOS_Thai: charSet = FX_CHARSET_Thai; break; case FX_CODEPAGE_Hangul: charSet = FX_CHARSET_Hangul; break; case FX_CODEPAGE_UTF16LE: charSet = FX_CHARSET_ANSI; break; case FX_CODEPAGE_MSWin_EasternEuropean: charSet = FX_CHARSET_MSWin_EasternEuropean; break; case FX_CODEPAGE_MSWin_Cyrillic: charSet = FX_CHARSET_MSWin_Cyrillic; break; case FX_CODEPAGE_MSWin_Greek: charSet = FX_CHARSET_MSWin_Greek; break; case FX_CODEPAGE_MSWin_Turkish: charSet = FX_CHARSET_MSWin_Turkish; break; case FX_CODEPAGE_MSWin_Hebrew: charSet = FX_CHARSET_MSWin_Hebrew; break; case FX_CODEPAGE_MSWin_Arabic: charSet = FX_CHARSET_MSWin_Arabic; break; case FX_CODEPAGE_MSWin_Baltic: charSet = FX_CHARSET_MSWin_Baltic; break; case FX_CODEPAGE_MSWin_Vietnamese: charSet = FX_CHARSET_MSWin_Vietnamese; break; case FX_CODEPAGE_Johab: charSet = FX_CHARSET_Johab; break; } return charSet; #else return 0; #endif } CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument) : m_pDocument(pDocument), m_pFormDict(nullptr), m_pFieldTree(pdfium::MakeUnique<CFieldTree>()), m_pFormNotify(nullptr) { CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); if (!pRoot) return; m_pFormDict = pRoot->GetDictFor("AcroForm"); if (!m_pFormDict) return; CPDF_Array* pFields = m_pFormDict->GetArrayFor("Fields"); if (!pFields) return; for (size_t i = 0; i < pFields->GetCount(); ++i) LoadField(pFields->GetDictAt(i), 0); } CPDF_InterForm::~CPDF_InterForm() {} bool CPDF_InterForm::s_bUpdateAP = true; bool CPDF_InterForm::IsUpdateAPEnabled() { return s_bUpdateAP; } void CPDF_InterForm::SetUpdateAP(bool bUpdateAP) { s_bUpdateAP = bUpdateAP; } ByteString CPDF_InterForm::GenerateNewResourceName( const CPDF_Dictionary* pResDict, const char* csType, int iMinLen, const char* csPrefix) { ByteString csStr = csPrefix; ByteString csBType = csType; if (csStr.IsEmpty()) { if (csBType == "ExtGState") csStr = "GS"; else if (csBType == "ColorSpace") csStr = "CS"; else if (csBType == "Font") csStr = "ZiTi"; else csStr = "Res"; } ByteString csTmp = csStr; int iCount = csStr.GetLength(); int m = 0; if (iMinLen > 0) { csTmp.clear(); while (m < iMinLen && m < iCount) csTmp += csStr[m++]; while (m < iMinLen) { csTmp += '0' + m % 10; m++; } } else { m = iCount; } if (!pResDict) return csTmp; CPDF_Dictionary* pDict = pResDict->GetDictFor(csType); if (!pDict) return csTmp; int num = 0; ByteString bsNum; while (true) { ByteString csKey = csTmp + bsNum; if (!pDict->KeyExist(csKey)) return csKey; if (m < iCount) csTmp += csStr[m++]; else bsNum = ByteString::Format("%d", num++); m++; } return csTmp; } CPDF_Font* CPDF_InterForm::AddStandardFont(CPDF_Document* pDocument, ByteString csFontName) { if (!pDocument || csFontName.IsEmpty()) return nullptr; if (csFontName == "ZapfDingbats") return pDocument->AddStandardFont(csFontName.c_str(), nullptr); CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI); return pDocument->AddStandardFont(csFontName.c_str(), &encoding); } ByteString CPDF_InterForm::GetNativeFont(uint8_t charSet, void* pLogFont) { ByteString csFontName; #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ LOGFONTA lf = {}; if (charSet == FX_CHARSET_ANSI) { csFontName = "Helvetica"; return csFontName; } bool bRet = false; if (charSet == FX_CHARSET_ShiftJIS) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MS Mincho", lf); } else if (charSet == FX_CHARSET_ChineseSimplified) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun", lf); } else if (charSet == FX_CHARSET_ChineseTraditional) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MingLiU", lf); } if (!bRet) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "Arial Unicode MS", lf); } if (!bRet) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "Microsoft Sans Serif", lf); } if (!bRet) { bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, nullptr, lf); } if (bRet) { if (pLogFont) memcpy(pLogFont, &lf, sizeof(LOGFONTA)); csFontName = lf.lfFaceName; return csFontName; } #endif return csFontName; } CPDF_Font* CPDF_InterForm::AddNativeFont(uint8_t charSet, CPDF_Document* pDocument) { if (!pDocument) return nullptr; #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ LOGFONTA lf; ByteString csFontName = GetNativeFont(charSet, &lf); if (!csFontName.IsEmpty()) { if (csFontName == "Helvetica") return AddStandardFont(pDocument, csFontName); return pDocument->AddWindowsFont(&lf, false, true); } #endif return nullptr; } CPDF_Font* CPDF_InterForm::AddNativeFont(CPDF_Document* pDocument) { return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr; } bool CPDF_InterForm::ValidateFieldName( WideString& csNewFieldName, int iType, const CPDF_FormField* pExcludedField, const CPDF_FormControl* pExcludedControl) const { if (csNewFieldName.IsEmpty()) return false; int iPos = 0; int iLength = csNewFieldName.GetLength(); WideString csSub; while (true) { while (iPos < iLength && (csNewFieldName[iPos] == L'.' || csNewFieldName[iPos] == L' ')) { iPos++; } if (iPos < iLength && !csSub.IsEmpty()) csSub += L'.'; while (iPos < iLength && csNewFieldName[iPos] != L'.') csSub += csNewFieldName[iPos++]; for (int i = csSub.GetLength() - 1; i > -1; i--) { if (csSub[i] != L' ' && csSub[i] != L'.') break; csSub.SetAt(i, L'\0'); } size_t dwCount = m_pFieldTree->m_Root.CountFields(); for (size_t m = 0; m < dwCount; ++m) { CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(m); if (!pField) continue; if (pField == pExcludedField) { if (!pExcludedControl || pField->CountControls() < 2) continue; } WideString csFullName = pField->GetFullName(); int iRet = CompareFieldName(csSub, csFullName); if (iRet == 1) { if (pField->GetFieldType() != iType) return false; } else if (iRet == 2 && csSub == csNewFieldName) { if (csFullName[iPos] == L'.') return false; } else if (iRet == 3 && csSub == csNewFieldName) { if (csNewFieldName[csFullName.GetLength()] == L'.') return false; } } if (iPos >= iLength) break; } if (csSub.IsEmpty()) return false; csNewFieldName = csSub; return true; } size_t CPDF_InterForm::CountFields(const WideString& csFieldName) const { if (csFieldName.IsEmpty()) return m_pFieldTree->m_Root.CountFields(); CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName); return pNode ? pNode->CountFields() : 0; } CPDF_FormField* CPDF_InterForm::GetField(uint32_t index, const WideString& csFieldName) const { if (csFieldName.IsEmpty()) return m_pFieldTree->m_Root.GetFieldAtIndex(index); CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName); return pNode ? pNode->GetFieldAtIndex(index) : nullptr; } CPDF_FormField* CPDF_InterForm::GetFieldByDict( CPDF_Dictionary* pFieldDict) const { if (!pFieldDict) return nullptr; WideString csWName = FPDF_GetFullName(pFieldDict); return m_pFieldTree->GetField(csWName); } CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage, const CFX_PointF& point, int* z_order) const { CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots"); if (!pAnnotList) return nullptr; for (size_t i = pAnnotList->GetCount(); i > 0; --i) { size_t annot_index = i - 1; CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index); if (!pAnnot) continue; const auto it = m_ControlMap.find(pAnnot); if (it == m_ControlMap.end()) continue; CPDF_FormControl* pControl = it->second.get(); if (!pControl->GetRect().Contains(point)) continue; if (z_order) *z_order = static_cast<int>(annot_index); return pControl; } return nullptr; } CPDF_FormControl* CPDF_InterForm::GetControlByDict( const CPDF_Dictionary* pWidgetDict) const { const auto it = m_ControlMap.find(pWidgetDict); return it != m_ControlMap.end() ? it->second.get() : nullptr; } bool CPDF_InterForm::NeedConstructAP() const { return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances"); } int CPDF_InterForm::CountFieldsInCalculationOrder() { if (!m_pFormDict) return 0; CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); return pArray ? pArray->GetCount() : 0; } CPDF_FormField* CPDF_InterForm::GetFieldInCalculationOrder(int index) { if (!m_pFormDict || index < 0) return nullptr; CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); if (!pArray) return nullptr; CPDF_Dictionary* pElement = ToDictionary(pArray->GetDirectObjectAt(index)); return pElement ? GetFieldByDict(pElement) : nullptr; } int CPDF_InterForm::FindFieldInCalculationOrder(const CPDF_FormField* pField) { if (!m_pFormDict || !pField) return -1; CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); if (!pArray) return -1; for (size_t i = 0; i < pArray->GetCount(); i++) { CPDF_Object* pElement = pArray->GetDirectObjectAt(i); if (pElement == pField->GetDict()) return i; } return -1; } CPDF_Font* CPDF_InterForm::GetFormFont(ByteString csNameTag) const { return GetFont(m_pFormDict.Get(), m_pDocument.Get(), csNameTag); } CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() const { if (!m_pFormDict) return CPDF_DefaultAppearance(); return CPDF_DefaultAppearance(m_pFormDict->GetStringFor("DA")); } int CPDF_InterForm::GetFormAlignment() const { return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0; } bool CPDF_InterForm::ResetForm(const std::vector<CPDF_FormField*>& fields, bool bIncludeOrExclude, bool bNotify) { if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0) return false; size_t nCount = m_pFieldTree->m_Root.CountFields(); for (size_t i = 0; i < nCount; ++i) { CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); if (!pField) continue; if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) pField->ResetField(bNotify); } if (bNotify && m_pFormNotify) m_pFormNotify->AfterFormReset(this); return true; } bool CPDF_InterForm::ResetForm(bool bNotify) { if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0) return false; size_t nCount = m_pFieldTree->m_Root.CountFields(); for (size_t i = 0; i < nCount; ++i) { CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); if (!pField) continue; pField->ResetField(bNotify); } if (bNotify && m_pFormNotify) m_pFormNotify->AfterFormReset(this); return true; } void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) { if (nLevel > nMaxRecursion) return; if (!pFieldDict) return; uint32_t dwParentObjNum = pFieldDict->GetObjNum(); CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids"); if (!pKids) { AddTerminalField(pFieldDict); return; } CPDF_Dictionary* pFirstKid = pKids->GetDictAt(0); if (!pFirstKid) return; if (pFirstKid->KeyExist("T") || pFirstKid->KeyExist("Kids")) { for (size_t i = 0; i < pKids->GetCount(); i++) { CPDF_Dictionary* pChildDict = pKids->GetDictAt(i); if (pChildDict) { if (pChildDict->GetObjNum() != dwParentObjNum) LoadField(pChildDict, nLevel + 1); } } } else { AddTerminalField(pFieldDict); } } bool CPDF_InterForm::HasXFAForm() const { return m_pFormDict && m_pFormDict->GetArrayFor("XFA"); } void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) { CPDF_Dictionary* pPageDict = pPage->m_pFormDict.Get(); if (!pPageDict) return; CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots"); if (!pAnnots) return; for (size_t i = 0; i < pAnnots->GetCount(); i++) { CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i); if (pAnnot && pAnnot->GetStringFor("Subtype") == "Widget") LoadField(pAnnot, 0); } } void CPDF_InterForm::AddTerminalField(CPDF_Dictionary* pFieldDict) { if (!pFieldDict->KeyExist("FT")) { // Key "FT" is required for terminal fields, it is also inheritable. CPDF_Dictionary* pParentDict = pFieldDict->GetDictFor("Parent"); if (!pParentDict || !pParentDict->KeyExist("FT")) return; } CPDF_Dictionary* pDict = pFieldDict; WideString csWName = FPDF_GetFullName(pFieldDict); if (csWName.IsEmpty()) return; CPDF_FormField* pField = nullptr; pField = m_pFieldTree->GetField(csWName); if (!pField) { CPDF_Dictionary* pParent = pFieldDict; if (!pFieldDict->KeyExist("T") && pFieldDict->GetStringFor("Subtype") == "Widget") { pParent = pFieldDict->GetDictFor("Parent"); if (!pParent) pParent = pFieldDict; } if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) { if (pFieldDict->KeyExist("FT")) { CPDF_Object* pFTValue = pFieldDict->GetDirectObjectFor("FT"); if (pFTValue) pParent->SetFor("FT", pFTValue->Clone()); } if (pFieldDict->KeyExist("Ff")) { CPDF_Object* pFfValue = pFieldDict->GetDirectObjectFor("Ff"); if (pFfValue) pParent->SetFor("Ff", pFfValue->Clone()); } } auto newField = pdfium::MakeUnique<CPDF_FormField>(this, pParent); pField = newField.get(); CPDF_Object* pTObj = pDict->GetObjectFor("T"); if (ToReference(pTObj)) { std::unique_ptr<CPDF_Object> pClone = pTObj->CloneDirectObject(); if (pClone) pDict->SetFor("T", std::move(pClone)); else pDict->SetNewFor<CPDF_Name>("T", ""); } if (!m_pFieldTree->SetField(csWName, std::move(newField))) return; } CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids"); if (pKids) { for (size_t i = 0; i < pKids->GetCount(); i++) { CPDF_Dictionary* pKid = pKids->GetDictAt(i); if (!pKid) continue; if (pKid->GetStringFor("Subtype") != "Widget") continue; AddControl(pField, pKid); } } else { if (pFieldDict->GetStringFor("Subtype") == "Widget") AddControl(pField, pFieldDict); } } CPDF_FormControl* CPDF_InterForm::AddControl(CPDF_FormField* pField, CPDF_Dictionary* pWidgetDict) { const auto it = m_ControlMap.find(pWidgetDict); if (it != m_ControlMap.end()) return it->second.get(); auto pNew = pdfium::MakeUnique<CPDF_FormControl>(pField, pWidgetDict); CPDF_FormControl* pControl = pNew.get(); m_ControlMap[pWidgetDict] = std::move(pNew); pField->AddFormControl(pControl); return pControl; } bool CPDF_InterForm::CheckRequiredFields( const std::vector<CPDF_FormField*>* fields, bool bIncludeOrExclude) const { size_t nCount = m_pFieldTree->m_Root.CountFields(); for (size_t i = 0; i < nCount; ++i) { CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); if (!pField) continue; int32_t iType = pField->GetType(); if (iType == CPDF_FormField::PushButton || iType == CPDF_FormField::CheckBox || iType == CPDF_FormField::ListBox) { continue; } uint32_t dwFlags = pField->GetFieldFlags(); // TODO(thestig): Look up these magic numbers and add constants for them. if (dwFlags & FORMFLAG_NOEXPORT) continue; bool bFind = true; if (fields) bFind = pdfium::ContainsValue(*fields, pField); if (bIncludeOrExclude == bFind) { const CPDF_Dictionary* pFieldDict = pField->GetDict(); if ((dwFlags & FORMFLAG_REQUIRED) != 0 && pFieldDict->GetStringFor("V").IsEmpty()) { return false; } } } return true; } std::unique_ptr<CFDF_Document> CPDF_InterForm::ExportToFDF( const WideString& pdf_path, bool bSimpleFileSpec) const { std::vector<CPDF_FormField*> fields; size_t nCount = m_pFieldTree->m_Root.CountFields(); for (size_t i = 0; i < nCount; ++i) fields.push_back(m_pFieldTree->m_Root.GetFieldAtIndex(i)); return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec); } std::unique_ptr<CFDF_Document> CPDF_InterForm::ExportToFDF( const WideString& pdf_path, const std::vector<CPDF_FormField*>& fields, bool bIncludeOrExclude, bool bSimpleFileSpec) const { std::unique_ptr<CFDF_Document> pDoc = CFDF_Document::CreateNewDoc(); if (!pDoc) return nullptr; CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDictFor("FDF"); if (!pdf_path.IsEmpty()) { if (bSimpleFileSpec) { WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path); pMainDict->SetNewFor<CPDF_String>( "F", ByteString::FromUnicode(wsFilePath), false); pMainDict->SetNewFor<CPDF_String>("UF", PDF_EncodeText(wsFilePath), false); } else { auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()); pNewDict->SetNewFor<CPDF_Name>("Type", "Filespec"); CPDF_FileSpec filespec(pNewDict.get()); filespec.SetFileName(pdf_path); pMainDict->SetFor("F", std::move(pNewDict)); } } CPDF_Array* pFields = pMainDict->SetNewFor<CPDF_Array>("Fields"); size_t nCount = m_pFieldTree->m_Root.CountFields(); for (size_t i = 0; i < nCount; ++i) { CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); if (!pField || pField->GetType() == CPDF_FormField::PushButton) continue; uint32_t dwFlags = pField->GetFieldFlags(); if (dwFlags & 0x04) continue; if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) { if ((dwFlags & 0x02) != 0 && pField->GetDict()->GetStringFor("V").IsEmpty()) { continue; } WideString fullname = FPDF_GetFullName(pField->GetFieldDict()); auto pFieldDict = pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()); pFieldDict->SetNewFor<CPDF_String>("T", fullname); if (pField->GetType() == CPDF_FormField::CheckBox || pField->GetType() == CPDF_FormField::RadioButton) { WideString csExport = pField->GetCheckValue(false); ByteString csBExport = PDF_EncodeText(csExport); CPDF_Object* pOpt = FPDF_GetFieldAttr(pField->GetDict(), "Opt"); if (pOpt) pFieldDict->SetNewFor<CPDF_String>("V", csBExport, false); else pFieldDict->SetNewFor<CPDF_Name>("V", csBExport); } else { CPDF_Object* pV = FPDF_GetFieldAttr(pField->GetDict(), "V"); if (pV) pFieldDict->SetFor("V", pV->CloneDirectObject()); } pFields->Add(std::move(pFieldDict)); } } return pDoc; } void CPDF_InterForm::FDF_ImportField(CPDF_Dictionary* pFieldDict, const WideString& parent_name, bool bNotify, int nLevel) { WideString name; if (!parent_name.IsEmpty()) name = parent_name + L"."; name += pFieldDict->GetUnicodeTextFor("T"); CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids"); if (pKids) { for (size_t i = 0; i < pKids->GetCount(); i++) { CPDF_Dictionary* pKid = pKids->GetDictAt(i); if (!pKid) continue; if (nLevel <= nMaxRecursion) FDF_ImportField(pKid, name, bNotify, nLevel + 1); } return; } if (!pFieldDict->KeyExist("V")) return; CPDF_FormField* pField = m_pFieldTree->GetField(name); if (!pField) return; WideString csWValue = GetFieldValue(*pFieldDict, m_bsEncoding); int iType = pField->GetFieldType(); if (bNotify && m_pFormNotify) { if (iType == FIELDTYPE_LISTBOX) { if (m_pFormNotify->BeforeSelectionChange(pField, csWValue) < 0) return; } else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) { if (m_pFormNotify->BeforeValueChange(pField, csWValue) < 0) return; } } pField->SetValue(csWValue); CPDF_FormField::Type eType = pField->GetType(); if ((eType == CPDF_FormField::ListBox || eType == CPDF_FormField::ComboBox) && pFieldDict->KeyExist("Opt")) { pField->SetOpt(pFieldDict->GetDirectObjectFor("Opt")->CloneDirectObject()); } if (bNotify && m_pFormNotify) { if (iType == FIELDTYPE_CHECKBOX || iType == FIELDTYPE_RADIOBUTTON) m_pFormNotify->AfterCheckedStatusChange(pField); else if (iType == FIELDTYPE_LISTBOX) m_pFormNotify->AfterSelectionChange(pField); else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD) m_pFormNotify->AfterValueChange(pField); } } void CPDF_InterForm::SetFormNotify(IPDF_FormNotify* pNotify) { m_pFormNotify = pNotify; }