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"
CFDF_Document()8 CFDF_Document::CFDF_Document() : CPDF_IndirectObjects(NULL)
9 {
10 m_pRootDict = NULL;
11 m_pFile = NULL;
12 m_bOwnFile = FALSE;
13 }
~CFDF_Document()14 CFDF_Document::~CFDF_Document()
15 {
16 if (m_bOwnFile && m_pFile) {
17 m_pFile->Release();
18 }
19 }
CreateNewDoc()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 }
ParseFile(FX_LPCSTR file_path)29 CFDF_Document* CFDF_Document::ParseFile(FX_LPCSTR file_path)
30 {
31 return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE);
32 }
ParseFile(FX_LPCWSTR file_path)33 CFDF_Document* CFDF_Document::ParseFile(FX_LPCWSTR file_path)
34 {
35 return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE);
36 }
ParseFile(IFX_FileRead * pFile,FX_BOOL bOwnFile)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 }
ParseMemory(FX_LPCBYTE pData,FX_DWORD size)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 }
ParseStream(IFX_FileRead * pFile,FX_BOOL bOwnFile)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 }
WriteBuf(CFX_ByteTextBuf & buf) const96 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 }
GetWin32Path() const112 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 }
WriteFile(FX_LPCSTR file_path) const123 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 }
WriteFile(FX_LPCWSTR file_path) const133 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 }
WriteFile(IFX_FileWrite * pFile) const143 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 }
ChangeSlash(FX_LPCWSTR str)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 }
FPDF_FileSpec_SetWin32Path(CPDF_Object * pFileSpec,const CFX_WideString & filepath)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 }
FPDF_FileSpec_GetWin32Path(const CPDF_Object * pFileSpec)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 }
225