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 11 CFDF_Document::CFDF_Document() : CPDF_IndirectObjectHolder(NULL) { 12 m_pRootDict = NULL; 13 m_pFile = NULL; 14 m_bOwnFile = FALSE; 15 } 16 CFDF_Document::~CFDF_Document() { 17 if (m_bOwnFile && m_pFile) { 18 m_pFile->Release(); 19 } 20 } 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 } 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 } 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 } 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 } 85 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 } 97 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 } 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 } 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 } 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