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