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 { 10 m_pRootDict = NULL; 11 m_pFile = NULL; 12 m_bOwnFile = FALSE; 13 } 14 CFDF_Document::~CFDF_Document() 15 { 16 if (m_bOwnFile && m_pFile) { 17 m_pFile->Release(); 18 } 19 } 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 } 29 CFDF_Document* CFDF_Document::ParseFile(FX_LPCSTR file_path) 30 { 31 return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE); 32 } 33 CFDF_Document* CFDF_Document::ParseFile(FX_LPCWSTR file_path) 34 { 35 return CFDF_Document::ParseFile(FX_CreateFileRead(file_path), TRUE); 36 } 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 } 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 } 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 } 96 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 } 112 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 } 123 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 } 133 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 } 143 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 } 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 } 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 } 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