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/fpdfapi/fpdf_serial.h"
CFDF_Document()8 CFDF_Document::CFDF_Document() : CPDF_IndirectObjects(NULL)
9 {
10     m_pRootDict = NULL;
11     m_pFile = NULL;
12     m_bOwnFile = FALSE;
13 }
~CFDF_Document()14 CFDF_Document::~CFDF_Document()
15 {
16     if (m_bOwnFile && m_pFile) {
17         m_pFile->Release();
18     }
19 }
CreateNewDoc()20 CFDF_Document* CFDF_Document::CreateNewDoc()
21 {
22     CFDF_Document* pDoc = new CFDF_Document;
23     pDoc->m_pRootDict = new CPDF_Dictionary;
24     pDoc->AddIndirectObject(pDoc->m_pRootDict);
25     CPDF_Dictionary* pFDFDict = new CPDF_Dictionary;
26     pDoc->m_pRootDict->SetAt(FX_BSTRC("FDF"), pFDFDict);
27     return pDoc;
28 }
ParseFile(IFX_FileRead * pFile,FX_BOOL bOwnFile)29 CFDF_Document* CFDF_Document::ParseFile(IFX_FileRead *pFile, FX_BOOL bOwnFile)
30 {
31   if (!pFile) {
32     return NULL;
33   }
34   CFDF_Document* pDoc = new CFDF_Document;
35   pDoc->ParseStream(pFile, bOwnFile);
36   if (pDoc->m_pRootDict == NULL) {
37     delete pDoc;
38     return NULL;
39   }
40   return pDoc;
41 }
ParseMemory(FX_LPCBYTE pData,FX_DWORD size)42 CFDF_Document* CFDF_Document::ParseMemory(FX_LPCBYTE pData, FX_DWORD size)
43 {
44     return CFDF_Document::ParseFile(FX_CreateMemoryStream((FX_LPBYTE)pData, size), TRUE);
45 }
ParseStream(IFX_FileRead * pFile,FX_BOOL bOwnFile)46 void CFDF_Document::ParseStream(IFX_FileRead *pFile, FX_BOOL bOwnFile)
47 {
48     m_pFile = pFile;
49     m_bOwnFile = bOwnFile;
50     CPDF_SyntaxParser parser;
51     parser.InitParser(m_pFile, 0);
52     while (1) {
53         FX_BOOL bNumber;
54         CFX_ByteString word = parser.GetNextWord(bNumber);
55         if (bNumber) {
56             FX_DWORD objnum = FXSYS_atoi(word);
57             word = parser.GetNextWord(bNumber);
58             if (!bNumber) {
59                 break;
60             }
61             word = parser.GetNextWord(bNumber);
62             if (word != FX_BSTRC("obj")) {
63                 break;
64             }
65             CPDF_Object* pObj = parser.GetObject(this, objnum, 0, FALSE);
66             if (pObj == NULL) {
67                 break;
68             }
69             InsertIndirectObject(objnum, pObj);
70             word = parser.GetNextWord(bNumber);
71             if (word != FX_BSTRC("endobj")) {
72                 break;
73             }
74         } else {
75             if (word != FX_BSTRC("trailer")) {
76                 break;
77             }
78             CPDF_Dictionary* pMainDict = (CPDF_Dictionary*)parser.GetObject(this, 0, 0, 0);
79             if (pMainDict == NULL || pMainDict->GetType() != PDFOBJ_DICTIONARY) {
80                 break;
81             }
82             m_pRootDict = pMainDict->GetDict(FX_BSTRC("Root"));
83             pMainDict->Release();
84             break;
85         }
86     }
87 }
WriteBuf(CFX_ByteTextBuf & buf) const88 FX_BOOL CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const
89 {
90     if (m_pRootDict == NULL) {
91         return FALSE;
92     }
93     buf << FX_BSTRC("%FDF-1.2\r\n");
94     FX_POSITION pos = m_IndirectObjs.GetStartPosition();
95     while(pos) {
96         size_t objnum;
97         CPDF_Object* pObj;
98         m_IndirectObjs.GetNextAssoc(pos, (FX_LPVOID&)objnum, (FX_LPVOID&)pObj);
99         buf << (FX_DWORD)objnum << FX_BSTRC(" 0 obj\r\n") << pObj << FX_BSTRC("\r\nendobj\r\n\r\n");
100     }
101     buf << FX_BSTRC("trailer\r\n<</Root ") << m_pRootDict->GetObjNum() << FX_BSTRC(" 0 R>>\r\n%%EOF\r\n");
102     return TRUE;
103 }
GetWin32Path() const104 CFX_WideString CFDF_Document::GetWin32Path() const
105 {
106     CPDF_Dictionary* pDict = m_pRootDict ? m_pRootDict->GetDict(FX_BSTRC("FDF")) : NULL;
107     CPDF_Object* pFileSpec = pDict ? pDict->GetElementValue(FX_BSTRC("F")) : NULL;
108     if (pFileSpec == NULL) {
109         return CFX_WideString();
110     }
111     if (pFileSpec->GetType() == PDFOBJ_STRING) {
112         return FPDF_FileSpec_GetWin32Path(m_pRootDict->GetDict(FX_BSTRC("FDF")));
113     }
114     return FPDF_FileSpec_GetWin32Path(pFileSpec);
115 }
ChangeSlash(FX_LPCWSTR str)116 static CFX_WideString ChangeSlash(FX_LPCWSTR str)
117 {
118     CFX_WideString result;
119     while (*str) {
120         if (*str == '\\') {
121             result += '/';
122         } else if (*str == '/') {
123             result += '\\';
124         } else {
125             result += *str;
126         }
127         str ++;
128     }
129     return result;
130 }
FPDF_FileSpec_SetWin32Path(CPDF_Object * pFileSpec,const CFX_WideString & filepath)131 void FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec, const CFX_WideString& filepath)
132 {
133     CFX_WideString result;
134     if (filepath.GetLength() > 1 && filepath[1] == ':') {
135         result = L"/";
136         result += filepath[0];
137         if (filepath[2] != '\\') {
138             result += '/';
139         }
140         result += ChangeSlash(filepath.c_str() + 2);
141     } else if (filepath.GetLength() > 1 && filepath[0] == '\\' && filepath[1] == '\\') {
142         result = ChangeSlash(filepath.c_str() + 1);
143     } else {
144         result = ChangeSlash(filepath.c_str());
145     }
146     if (pFileSpec->GetType() == PDFOBJ_STRING) {
147         pFileSpec->SetString(CFX_ByteString::FromUnicode(result));
148     } else if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {
149         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(result));
150         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(result));
151         ((CPDF_Dictionary*)pFileSpec)->RemoveAt(FX_BSTRC("FS"));
152     }
153 }
FPDF_FileSpec_GetWin32Path(const CPDF_Object * pFileSpec)154 CFX_WideString	FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec)
155 {
156     CFX_WideString wsFileName;
157     if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {
158         CPDF_Dictionary* pDict = (CPDF_Dictionary*)pFileSpec;
159         wsFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));
160         if (wsFileName.IsEmpty()) {
161             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));
162         }
163         if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {
164             return wsFileName;
165         }
166         if (wsFileName.IsEmpty() && pDict->KeyExist(FX_BSTRC("DOS"))) {
167             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));
168         }
169     }
170     else if (!pFileSpec)
171         wsFileName = CFX_WideString();
172     else {
173         wsFileName = CFX_WideString::FromLocal(pFileSpec->GetString());
174     }
175     if (wsFileName[0] != '/') {
176         return ChangeSlash(wsFileName.c_str());
177     }
178     if (wsFileName[2] == '/') {
179         CFX_WideString result;
180         result += wsFileName[1];
181         result += ':';
182         result += ChangeSlash(wsFileName.c_str() + 2);
183         return result;
184     } else {
185         CFX_WideString result;
186         result += '\\';
187         result += ChangeSlash(wsFileName.c_str());
188         return result;
189     }
190 }
191