Clean up CPDF_AnnotList.
[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       if (CPDF_Dictionary* pMainDict =
74               ToDictionary(parser.GetObject(this, 0, 0, 0))) {
75         m_pRootDict = pMainDict->GetDict(FX_BSTRC("Root"));
76         pMainDict->Release();
77       }
78       break;
79     }
80   }
81 }
82 FX_BOOL CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const {
83   if (m_pRootDict == NULL) {
84     return FALSE;
85   }
86   buf << FX_BSTRC("%FDF-1.2\r\n");
87   FX_POSITION pos = m_IndirectObjs.GetStartPosition();
88   while (pos) {
89     size_t objnum;
90     CPDF_Object* pObj;
91     m_IndirectObjs.GetNextAssoc(pos, (void*&)objnum, (void*&)pObj);
92     buf << (FX_DWORD)objnum << FX_BSTRC(" 0 obj\r\n") << pObj
93         << FX_BSTRC("\r\nendobj\r\n\r\n");
94   }
95   buf << FX_BSTRC("trailer\r\n<</Root ") << m_pRootDict->GetObjNum()
96       << FX_BSTRC(" 0 R>>\r\n%%EOF\r\n");
97   return TRUE;
98 }
99 CFX_WideString CFDF_Document::GetWin32Path() const {
100   CPDF_Dictionary* pDict =
101       m_pRootDict ? m_pRootDict->GetDict(FX_BSTRC("FDF")) : NULL;
102   CPDF_Object* pFileSpec = pDict ? pDict->GetElementValue(FX_BSTRC("F")) : NULL;
103   if (!pFileSpec)
104     return CFX_WideString();
105   if (pFileSpec->IsString())
106     return FPDF_FileSpec_GetWin32Path(m_pRootDict->GetDict(FX_BSTRC("FDF")));
107   return FPDF_FileSpec_GetWin32Path(pFileSpec);
108 }
109 static CFX_WideString ChangeSlash(const FX_WCHAR* str) {
110   CFX_WideString result;
111   while (*str) {
112     if (*str == '\\') {
113       result += '/';
114     } else if (*str == '/') {
115       result += '\\';
116     } else {
117       result += *str;
118     }
119     str++;
120   }
121   return result;
122 }
123 void FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec,
124                                 const CFX_WideString& filepath) {
125   CFX_WideString result;
126   if (filepath.GetLength() > 1 && filepath[1] == ':') {
127     result = L"/";
128     result += filepath[0];
129     if (filepath[2] != '\\') {
130       result += '/';
131     }
132     result += ChangeSlash(filepath.c_str() + 2);
133   } else if (filepath.GetLength() > 1 && filepath[0] == '\\' &&
134              filepath[1] == '\\') {
135     result = ChangeSlash(filepath.c_str() + 1);
136   } else {
137     result = ChangeSlash(filepath.c_str());
138   }
139
140   if (pFileSpec->IsString()) {
141     pFileSpec->SetString(CFX_ByteString::FromUnicode(result));
142   } else if (CPDF_Dictionary* pFileDict = pFileSpec->AsDictionary()) {
143     pFileDict->SetAtString(FX_BSTRC("F"), CFX_ByteString::FromUnicode(result));
144     pFileDict->SetAtString(FX_BSTRC("UF"), PDF_EncodeText(result));
145     pFileDict->RemoveAt(FX_BSTRC("FS"));
146   }
147 }
148 CFX_WideString FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec) {
149   CFX_WideString wsFileName;
150   if (!pFileSpec) {
151     wsFileName = CFX_WideString();
152   } else if (const CPDF_Dictionary* pDict = pFileSpec->AsDictionary()) {
153     wsFileName = pDict->GetUnicodeText(FX_BSTRC("UF"));
154     if (wsFileName.IsEmpty()) {
155       wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("F")));
156     }
157     if (pDict->GetString(FX_BSTRC("FS")) == FX_BSTRC("URL")) {
158       return wsFileName;
159     }
160     if (wsFileName.IsEmpty() && pDict->KeyExist(FX_BSTRC("DOS"))) {
161       wsFileName = CFX_WideString::FromLocal(pDict->GetString(FX_BSTRC("DOS")));
162     }
163   } else {
164     wsFileName = CFX_WideString::FromLocal(pFileSpec->GetString());
165   }
166   if (wsFileName[0] != '/') {
167     return ChangeSlash(wsFileName.c_str());
168   }
169   if (wsFileName[2] == '/') {
170     CFX_WideString result;
171     result += wsFileName[1];
172     result += ':';
173     result += ChangeSlash(wsFileName.c_str() + 2);
174     return result;
175   }
176   CFX_WideString result;
177   result += '\\';
178   result += ChangeSlash(wsFileName.c_str());
179   return result;
180 }