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/fpdfapi/parser/cfdf_document.h"
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "core/fpdfapi/edit/cpdf_creator.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
15 #include "third_party/base/ptr_util.h"
16 
CFDF_Document()17 CFDF_Document::CFDF_Document()
18     : CPDF_IndirectObjectHolder(), m_pRootDict(nullptr) {}
19 
~CFDF_Document()20 CFDF_Document::~CFDF_Document() {}
21 
CreateNewDoc()22 std::unique_ptr<CFDF_Document> CFDF_Document::CreateNewDoc() {
23   auto pDoc = pdfium::MakeUnique<CFDF_Document>();
24   pDoc->m_pRootDict = pDoc->NewIndirect<CPDF_Dictionary>();
25   pDoc->m_pRootDict->SetNewFor<CPDF_Dictionary>("FDF");
26   return pDoc;
27 }
28 
ParseFile(const CFX_RetainPtr<IFX_SeekableReadStream> & pFile)29 std::unique_ptr<CFDF_Document> CFDF_Document::ParseFile(
30     const CFX_RetainPtr<IFX_SeekableReadStream>& pFile) {
31   if (!pFile)
32     return nullptr;
33 
34   auto pDoc = pdfium::MakeUnique<CFDF_Document>();
35   pDoc->ParseStream(pFile);
36   return pDoc->m_pRootDict ? std::move(pDoc) : nullptr;
37 }
38 
ParseMemory(uint8_t * pData,uint32_t size)39 std::unique_ptr<CFDF_Document> CFDF_Document::ParseMemory(uint8_t* pData,
40                                                           uint32_t size) {
41   return CFDF_Document::ParseFile(IFX_MemoryStream::Create(pData, size));
42 }
43 
ParseStream(const CFX_RetainPtr<IFX_SeekableReadStream> & pFile)44 void CFDF_Document::ParseStream(
45     const CFX_RetainPtr<IFX_SeekableReadStream>& pFile) {
46   m_pFile = pFile;
47   CPDF_SyntaxParser parser;
48   parser.InitParser(m_pFile, 0);
49   while (1) {
50     bool bNumber;
51     CFX_ByteString word = parser.GetNextWord(&bNumber);
52     if (bNumber) {
53       uint32_t objnum = FXSYS_atoui(word.c_str());
54       if (!objnum)
55         break;
56 
57       word = parser.GetNextWord(&bNumber);
58       if (!bNumber)
59         break;
60 
61       word = parser.GetNextWord(nullptr);
62       if (word != "obj")
63         break;
64 
65       std::unique_ptr<CPDF_Object> pObj =
66           parser.GetObject(this, objnum, 0, true);
67       if (!pObj)
68         break;
69 
70       ReplaceIndirectObjectIfHigherGeneration(objnum, std::move(pObj));
71       word = parser.GetNextWord(nullptr);
72       if (word != "endobj")
73         break;
74     } else {
75       if (word != "trailer")
76         break;
77 
78       std::unique_ptr<CPDF_Dictionary> pMainDict =
79           ToDictionary(parser.GetObject(this, 0, 0, true));
80       if (pMainDict)
81         m_pRootDict = pMainDict->GetDictFor("Root");
82 
83       break;
84     }
85   }
86 }
87 
WriteBuf(CFX_ByteTextBuf & buf) const88 bool CFDF_Document::WriteBuf(CFX_ByteTextBuf& buf) const {
89   if (!m_pRootDict)
90     return false;
91 
92   buf << "%FDF-1.2\r\n";
93   for (const auto& pair : *this)
94     buf << pair.first << " 0 obj\r\n"
95         << pair.second.get() << "\r\nendobj\r\n\r\n";
96 
97   buf << "trailer\r\n<</Root " << m_pRootDict->GetObjNum()
98       << " 0 R>>\r\n%%EOF\r\n";
99   return true;
100 }
101