Convert all line endings to LF.
[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_Object* pFileSpec = m_pRootDict->GetDict(FX_BSTRC("FDF"))->GetElementValue(FX_BSTRC("F"));
115     if (pFileSpec == NULL) {
116         return CFX_WideString();
117     }
118     if (pFileSpec->GetType() == PDFOBJ_STRING) {
119         return FPDF_FileSpec_GetWin32Path(m_pRootDict->GetDict(FX_BSTRC("FDF")));
120     }
121     return FPDF_FileSpec_GetWin32Path(pFileSpec);
122 }
123 FX_BOOL CFDF_Document::WriteFile(FX_LPCSTR file_path) const
124 {
125     IFX_FileWrite *pFile = FX_CreateFileWrite(file_path);
126     if (!pFile) {
127         return FALSE;
128     }
129     FX_BOOL bRet = WriteFile(pFile);
130     pFile->Release();
131     return bRet;
132 }
133 FX_BOOL CFDF_Document::WriteFile(FX_LPCWSTR file_path) const
134 {
135     IFX_FileWrite *pFile = FX_CreateFileWrite(file_path);
136     if (!pFile) {
137         return FALSE;
138     }
139     FX_BOOL bRet = WriteFile(pFile);
140     pFile->Release();
141     return bRet;
142 }
143 FX_BOOL CFDF_Document::WriteFile(IFX_FileWrite *pFile) const
144 {
145     CFX_ByteTextBuf buf;
146     WriteBuf(buf);
147     FX_BOOL bRet = pFile->WriteBlock(buf.GetBuffer(), buf.GetSize());
148     if (bRet) {
149         pFile->Flush();
150     }
151     return bRet;
152 }
153 static CFX_WideString ChangeSlash(FX_LPCWSTR str)
154 {
155     CFX_WideString result;
156     while (*str) {
157         if (*str == '\\') {
158             result += '/';
159         } else if (*str == '/') {
160             result += '\\';
161         } else {
162             result += *str;
163         }
164         str ++;
165     }
166     return result;
167 }
168 void FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec, const CFX_WideString& filepath)
169 {
170     CFX_WideString result;
171     if (filepath.GetLength() > 1 && filepath[1] == ':') {
172         result = L"/";
173         result += filepath[0];
174         if (filepath[2] != '\\') {
175             result += '/';
176         }
177         result += ChangeSlash((FX_LPCWSTR)filepath + 2);
178     } else if (filepath.GetLength() > 1 && filepath[0] == '\\' && filepath[1] == '\\') {
179         result = ChangeSlash((FX_LPCWSTR)filepath + 1);
180     } else {
181         result = ChangeSlash(filepath);
182     }
183     if (pFileSpec->GetType() == PDFOBJ_STRING) {
184         pFileSpec->SetString(CFX_ByteString::FromUnicode(result));
185     } else if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {
186         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(result));
187         ((CPDF_Dictionary*)pFileSpec)->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(result));
188         ((CPDF_Dictionary*)pFileSpec)->RemoveAt(FX_BSTRC("FS"));
189     }
190 }
191 CFX_WideString  FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec)
192 {
193     CFX_WideString wsFileName;
194     if (pFileSpec->GetType() == PDFOBJ_DICTIONARY) {
195         CPDF_Dictionary* pDict = (CPDF_Dictionary*)pFileSpec;
196         wsFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));
197         if (wsFileName.IsEmpty()) {
198             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));
199         }
200         if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {
201             return wsFileName;
202         }
203         if (wsFileName.IsEmpty() && pDict->KeyExist(FX_BSTRC("DOS"))) {
204             wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));
205         }
206     } else {
207         wsFileName = CFX_WideString::FromLocal(pFileSpec->GetString());
208     }
209     if (wsFileName[0] != '/') {
210         return ChangeSlash(wsFileName);
211     }
212     if (wsFileName[2] == '/') {
213         CFX_WideString result;
214         result += wsFileName[1];
215         result += ':';
216         result += ChangeSlash(((FX_LPCWSTR)wsFileName) + 2);
217         return result;
218     } else {
219         CFX_WideString result;
220         result += '\\';
221         result += ChangeSlash(wsFileName);
222         return result;
223     }
224 }