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