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