Initial commit.
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_fdf.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fpdfapi/fpdf_serial.h"\r
8 CFDF_Document::CFDF_Document() : CPDF_IndirectObjects(NULL)\r
9 {\r
10     m_pRootDict = NULL;\r
11     m_pFile = NULL;\r
12     m_bOwnFile = FALSE;\r
13 }\r
14 CFDF_Document::~CFDF_Document()\r
15 {\r
16     if (m_bOwnFile && m_pFile) {\r
17         m_pFile->Release();\r
18     }\r
19 }\r
20 CFDF_Document* CFDF_Document::CreateNewDoc()\r
21 {\r
22     CFDF_Document* pDoc = FX_NEW CFDF_Document;\r
23     pDoc->m_pRootDict = FX_NEW CPDF_Dictionary;\r
24     pDoc->AddIndirectObject(pDoc->m_pRootDict);\r
25     CPDF_Dictionary* pFDFDict = FX_NEW CPDF_Dictionary;\r
26     pDoc->m_pRootDict->SetAt(FX_BSTRC("FDF"), pFDFDict);\r
27     return pDoc;\r
28 }\r
29 CFDF_Document* CFDF_Document::ParseFile(FX_LPCSTR file_path)\r
30 {\r
31     return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE);\r
32 }\r
33 CFDF_Document* CFDF_Document::ParseFile(FX_LPCWSTR file_path)\r
34 {\r
35     return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE);\r
36 }\r
37 CFDF_Document* CFDF_Document::ParseFile(IFX_FileRead *pFile, FX_BOOL bOwnFile)\r
38 {\r
39     if (!pFile) {\r
40         return NULL;\r
41     }\r
42     CFDF_Document* pDoc = FX_NEW CFDF_Document;\r
43     pDoc->ParseStream(pFile, bOwnFile);\r
44     if (pDoc->m_pRootDict == NULL) {\r
45         delete pDoc;\r
46         return NULL;\r
47     }\r
48     return pDoc;\r
49 }\r
50 CFDF_Document* CFDF_Document::ParseMemory(FX_LPCBYTE pData, FX_DWORD size)\r
51 {\r
52     return CFDF_Document::ParseFile(FX_CreateMemoryStream((FX_LPBYTE)pData, size), TRUE);\r
53 }\r
54 void CFDF_Document::ParseStream(IFX_FileRead *pFile, FX_BOOL bOwnFile)\r
55 {\r
56     m_pFile = pFile;\r
57     m_bOwnFile = bOwnFile;\r
58     CPDF_SyntaxParser parser;\r
59     parser.InitParser(m_pFile, 0);\r
60     while (1) {\r
61         FX_BOOL bNumber;\r
62         CFX_ByteString word = parser.GetNextWord(bNumber);\r
63         if (bNumber) {\r
64             FX_DWORD objnum = FXSYS_atoi(word);\r
65             word = parser.GetNextWord(bNumber);\r
66             if (!bNumber) {\r
67                 break;\r
68             }\r
69             word = parser.GetNextWord(bNumber);\r
70             if (word != FX_BSTRC("obj")) {\r
71                 break;\r
72             }\r
73             CPDF_Object* pObj = parser.GetObject(this, objnum, 0, FALSE);\r
74             if (pObj == NULL) {\r
75                 break;\r
76             }\r
77             InsertIndirectObject(objnum, pObj);\r
78             word = parser.GetNextWord(bNumber);\r
79             if (word != FX_BSTRC("endobj")) {\r
80                 break;\r
81             }\r
82         } else {\r
83             if (word != FX_BSTRC("trailer")) {\r
84                 break;\r
85             }\r
86             CPDF_Dictionary* pMainDict = (CPDF_Dictionary*)parser.GetObject(this, 0, 0, 0);\r
87             if (pMainDict == NULL || pMainDict->GetType() != PDFOBJ_DICTIONARY) {\r
88                 break;\r
89             }\r
90             m_pRootDict = pMainDict->GetDict(FX_BSTRC("Root"));\r
91             pMainDict->Release();\r
92             break;\r
93         }\r
94     }\r
95 }\r
96 FX_BOOL CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const\r
97 {\r
98     if (m_pRootDict == NULL) {\r
99         return FALSE;\r
100     }\r
101     buf << FX_BSTRC("%FDF-1.2\r\n");\r
102     FX_POSITION pos = m_IndirectObjs.GetStartPosition();\r
103     while(pos) {\r
104         size_t objnum;\r
105         CPDF_Object* pObj;\r
106         m_IndirectObjs.GetNextAssoc(pos, (FX_LPVOID&)objnum, (FX_LPVOID&)pObj);\r
107         buf << (FX_DWORD)objnum << FX_BSTRC(" 0 obj\r\n") << pObj << FX_BSTRC("\r\nendobj\r\n\r\n");\r
108     }\r
109     buf << FX_BSTRC("trailer\r\n<</Root ") << m_pRootDict->GetObjNum() << FX_BSTRC(" 0 R>>\r\n%%EOF\r\n");\r
110     return TRUE;\r
111 }\r
112 CFX_WideString CFDF_Document::GetWin32Path() const\r
113 {\r
114     CPDF_Object* pFileSpec = m_pRootDict->GetDict(FX_BSTRC("FDF"))->GetElementValue(FX_BSTRC("F"));\r
115     if (pFileSpec == NULL) {\r
116         return CFX_WideString();\r
117     }\r
118     if (pFileSpec->GetType() == PDFOBJ_STRING) {\r
119         return FPDF_FileSpec_GetWin32Path(m_pRootDict->GetDict(FX_BSTRC("FDF")));\r
120     }\r
121     return FPDF_FileSpec_GetWin32Path(pFileSpec);\r
122 }\r
123 FX_BOOL CFDF_Document::WriteFile(FX_LPCSTR file_path) const\r
124 {\r
125     IFX_FileWrite *pFile = FX_CreateFileWrite(file_path);\r
126     if (!pFile) {\r
127         return FALSE;\r
128     }\r
129     FX_BOOL bRet = WriteFile(pFile);\r
130     pFile->Release();\r
131     return bRet;\r
132 }\r
133 FX_BOOL CFDF_Document::WriteFile(FX_LPCWSTR file_path) const\r
134 {\r
135     IFX_FileWrite *pFile = FX_CreateFileWrite(file_path);\r
136     if (!pFile) {\r
137         return FALSE;\r
138     }\r
139     FX_BOOL bRet = WriteFile(pFile);\r
140     pFile->Release();\r
141     return bRet;\r
142 }\r
143 FX_BOOL CFDF_Document::WriteFile(IFX_FileWrite *pFile) const\r
144 {\r
145     CFX_ByteTextBuf buf;\r
146     WriteBuf(buf);\r
147     FX_BOOL bRet = pFile->WriteBlock(buf.GetBuffer(), buf.GetSize());\r
148     if (bRet) {\r
149         pFile->Flush();\r
150     }\r
151     return bRet;\r
152 }\r
153 static CFX_WideString ChangeSlash(FX_LPCWSTR str)\r
154 {\r
155     CFX_WideString result;\r
156     while (*str) {\r
157         if (*str == '\\') {\r
158             result += '/';\r
159         } else if (*str == '/') {\r
160             result += '\\';\r
161         } else {\r
162             result += *str;\r
163         }\r
164         str ++;\r
165     }\r
166     return result;\r
167 }\r
168 void FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec, const CFX_WideString& filepath)\r
169 {\r
170     CFX_WideString result;\r
171     if (filepath.GetLength() > 1 && filepath[1] == ':') {\r
172         result = L"/";\r
173         result += filepath[0];\r
174         if (filepath[2] != '\\') {\r
175             result += '/';\r
176         }\r
177         result += ChangeSlash((FX_LPCWSTR)filepath + 2);\r
178     } else if (filepath.GetLength() > 1 && filepath[0] == '\\' && filepath[1] == '\\') {\r
179         result = ChangeSlash((FX_LPCWSTR)filepath + 1);\r
180     } else {\r
181         result = ChangeSlash(filepath);\r
182     }\r
183     if (pFileSpec->GetType() == PDFOBJ_STRING) {\r
184         pFileSpec->SetString(CFX_ByteString::FromUnicode(result));\r
185     } else if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {\r
186         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(result));\r
187         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(result));\r
188         ((CPDF_Dictionary*)pFileSpec)->RemoveAt(FX_BSTRC("FS"));\r
189     }\r
190 }\r
191 CFX_WideString  FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec)\r
192 {\r
193     CFX_WideString wsFileName;\r
194     if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {\r
195         CPDF_Dictionary* pDict = (CPDF_Dictionary*)pFileSpec;\r
196         wsFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));\r
197         if (wsFileName.IsEmpty()) {\r
198             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));\r
199         }\r
200         if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {\r
201             return wsFileName;\r
202         }\r
203         if (wsFileName.IsEmpty() && pDict->KeyExist(FX_BSTRC("DOS"))) {\r
204             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));\r
205         }\r
206     } else {\r
207         wsFileName = CFX_WideString::FromLocal(pFileSpec->GetString());\r
208     }\r
209     if (wsFileName[0] != '/') {\r
210         return ChangeSlash(wsFileName);\r
211     }\r
212     if (wsFileName[2] == '/') {\r
213         CFX_WideString result;\r
214         result += wsFileName[1];\r
215         result += ':';\r
216         result += ChangeSlash(((FX_LPCWSTR)wsFileName) + 2);\r
217         return result;\r
218     } else {\r
219         CFX_WideString result;\r
220         result += '\\';\r
221         result += ChangeSlash(wsFileName);\r
222         return result;\r
223     }\r
224 }\r