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 "../../include/fpdfdoc/fpdf_doc.h"
8#include "../../include/fxcrt/fx_xml.h"
9typedef struct _PDFDOC_METADATA {
10    CPDF_Document *m_pDoc;
11    CXML_Element *m_pXmlElmnt;
12    CXML_Element *m_pElmntRdf;
13    CFX_CMapByteStringToPtr *m_pStringMap;
14} PDFDOC_METADATA, * PDFDOC_LPMETADATA;
15typedef PDFDOC_METADATA const * PDFDOC_LPCMETADATA;
16const FX_LPCSTR gs_FPDFDOC_Metadata_Titles[] = {
17    "Title", "title",
18    "Subject", "description",
19    "Author", "creator",
20    "Keywords", "Keywords",
21    "Producer", "Producer",
22    "Creator", "CreatorTool",
23    "CreationDate", "CreateDate",
24    "ModDate", "ModifyDate",
25    "MetadataDate", "MetadataDate"
26};
27CPDF_Metadata::CPDF_Metadata()
28{
29    m_pData = FX_Alloc(PDFDOC_METADATA, 1);
30    FXSYS_memset32(m_pData, 0, sizeof(PDFDOC_METADATA));
31    CFX_CMapByteStringToPtr *&pStringMap = ((PDFDOC_LPMETADATA)m_pData)->m_pStringMap;
32    pStringMap = FX_NEW(CFX_CMapByteStringToPtr);
33    if (pStringMap != NULL) {
34        CFX_ByteString bstr;
35        for (int i = 0; i < 18; i += 2) {
36            bstr = gs_FPDFDOC_Metadata_Titles[i];
37            pStringMap->AddValue(bstr, (void*)gs_FPDFDOC_Metadata_Titles[i + 1]);
38        }
39    }
40}
41CPDF_Metadata::~CPDF_Metadata()
42{
43    FXSYS_assert(m_pData != NULL);
44    CXML_Element *&p = ((PDFDOC_LPMETADATA)m_pData)->m_pXmlElmnt;
45    if (p) {
46        delete p;
47    }
48    CFX_CMapByteStringToPtr *pStringMap = ((PDFDOC_LPMETADATA)m_pData)->m_pStringMap;
49    if (pStringMap) {
50        pStringMap->RemoveAll();
51        FX_Free(pStringMap);
52    }
53    FX_Free(m_pData);
54}
55void CPDF_Metadata::LoadDoc(CPDF_Document *pDoc)
56{
57    FXSYS_assert(pDoc != NULL);
58    ((PDFDOC_LPMETADATA)m_pData)->m_pDoc = pDoc;
59    CPDF_Dictionary *pRoot = pDoc->GetRoot();
60    CPDF_Stream *pStream = pRoot->GetStream(FX_BSTRC("Metadata"));
61    if (!pStream) {
62        return;
63    }
64    CPDF_StreamAcc acc;
65    acc.LoadAllData(pStream, FALSE);
66    int size = acc.GetSize();
67    FX_LPCBYTE pBuf = acc.GetData();
68    CXML_Element *&pXmlElmnt = ((PDFDOC_LPMETADATA)m_pData)->m_pXmlElmnt;
69    pXmlElmnt = CXML_Element::Parse(pBuf, size);
70    if (!pXmlElmnt) {
71        return;
72    }
73    CXML_Element *&pElmntRdf = ((PDFDOC_LPMETADATA)m_pData)->m_pElmntRdf;
74    if (pXmlElmnt->GetTagName() == FX_BSTRC("RDF")) {
75        pElmntRdf = pXmlElmnt;
76    } else {
77        pElmntRdf = pXmlElmnt->GetElement(NULL, FX_BSTRC("RDF"));
78    }
79}
80FX_INT32 CPDF_Metadata::GetString(FX_BSTR bsItem, CFX_WideString &wsStr)
81{
82    if (!((PDFDOC_LPMETADATA)m_pData)->m_pXmlElmnt) {
83        return -1;
84    }
85    if (!((PDFDOC_LPMETADATA)m_pData)->m_pStringMap) {
86        return -1;
87    }
88    void *szTag;
89    if (!((PDFDOC_LPMETADATA)m_pData)->m_pStringMap->Lookup(bsItem, szTag)) {
90        return -1;
91    }
92    CFX_ByteString bsTag = (FX_LPCSTR)szTag;
93    wsStr = L"";
94    CXML_Element *pElmntRdf = ((PDFDOC_LPMETADATA)m_pData)->m_pElmntRdf;
95    if (!pElmntRdf) {
96        return -1;
97    }
98    int nChild = pElmntRdf->CountChildren();
99    for (int i = 0; i < nChild; i++) {
100        CXML_Element *pTag = pElmntRdf->GetElement(NULL, FX_BSTRC("Description"), i);
101        if (!pTag) {
102            continue;
103        }
104        if (bsItem == FX_BSTRC("Title") || bsItem == FX_BSTRC("Subject")) {
105            CXML_Element *pElmnt = pTag->GetElement(NULL, bsTag);
106            if (!pElmnt) {
107                continue;
108            }
109            pElmnt = pElmnt->GetElement(NULL, FX_BSTRC("Alt"));
110            if (!pElmnt) {
111                continue;
112            }
113            pElmnt = pElmnt->GetElement(NULL, FX_BSTRC("li"));
114            if (!pElmnt) {
115                continue;
116            }
117            wsStr = pElmnt->GetContent(0);
118            return wsStr.GetLength();
119        } else if (bsItem == FX_BSTRC("Author")) {
120            CXML_Element *pElmnt = pTag->GetElement(NULL, bsTag);
121            if (!pElmnt) {
122                continue;
123            }
124            pElmnt = pElmnt->GetElement(NULL, FX_BSTRC("Seq"));
125            if (!pElmnt) {
126                continue;
127            }
128            pElmnt = pElmnt->GetElement(NULL, FX_BSTRC("li"));
129            if (!pElmnt) {
130                continue;
131            }
132            wsStr = pElmnt->GetContent(0);
133            return wsStr.GetLength();
134        } else {
135            CXML_Element *pElmnt = pTag->GetElement(NULL, bsTag);
136            if (!pElmnt) {
137                continue;
138            }
139            wsStr = pElmnt->GetContent(0);
140            return wsStr.GetLength();
141        }
142    }
143    return -1;
144}
145CXML_Element* CPDF_Metadata::GetRoot() const
146{
147    return ((PDFDOC_LPMETADATA)m_pData)->m_pXmlElmnt;
148}
149CXML_Element* CPDF_Metadata::GetRDF() const
150{
151    return ((PDFDOC_LPMETADATA)m_pData)->m_pElmntRdf;
152}
153