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