Home | History | Annotate | Download | only in fpdf_parser
      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