blob: 70d136b890f95e158baecebd98ffee43b3a7646c [file] [log] [blame]
Wei Li5227e572016-03-04 15:49:17 -08001// Copyright 2016 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#include "public/fpdf_doc.h"
6
7#include <memory>
8#include <vector>
9
dsinclair39c62fd2016-09-29 12:49:17 -070010#include "core/fpdfapi/cpdf_modulemgr.h"
dsinclairc6c425a2016-09-29 12:01:30 -070011#include "core/fpdfapi/fpdf_parser/cpdf_document.h"
12#include "core/fpdfapi/fpdf_parser/cpdf_name.h"
13#include "core/fpdfapi/fpdf_parser/cpdf_number.h"
14#include "core/fpdfapi/fpdf_parser/cpdf_parser.h"
15#include "core/fpdfapi/fpdf_parser/cpdf_reference.h"
16#include "core/fpdfapi/fpdf_parser/cpdf_string.h"
Wei Li5227e572016-03-04 15:49:17 -080017#include "testing/gtest/include/gtest/gtest.h"
18#include "testing/test_support.h"
19
20#ifdef PDF_ENABLE_XFA
dsinclairbec76922016-09-29 16:52:30 -070021#include "fpdfsdk/fpdfxfa/fpdfxfa_app.h"
22#include "fpdfsdk/fpdfxfa/fpdfxfa_doc.h"
Wei Li5227e572016-03-04 15:49:17 -080023#endif // PDF_ENABLE_XFA
24
25class CPDF_TestDocument : public CPDF_Document {
26 public:
dsinclaircedaa552016-08-24 11:12:19 -070027 CPDF_TestDocument() : CPDF_Document(std::unique_ptr<CPDF_Parser>()) {}
thestig931bf372016-04-26 22:24:30 -070028
Wei Li5227e572016-03-04 15:49:17 -080029 void SetRoot(CPDF_Dictionary* root) { m_pRootDict = root; }
30 CPDF_IndirectObjectHolder* GetHolder() { return this; }
31};
32
33#ifdef PDF_ENABLE_XFA
34class CPDF_TestXFADocument : public CPDFXFA_Document {
35 public:
36 CPDF_TestXFADocument()
dsinclaircedaa552016-08-24 11:12:19 -070037 : CPDFXFA_Document(WrapUnique(new CPDF_TestDocument()),
38 CPDFXFA_App::GetInstance()) {}
Wei Li5227e572016-03-04 15:49:17 -080039
40 void SetRoot(CPDF_Dictionary* root) {
41 reinterpret_cast<CPDF_TestDocument*>(GetPDFDoc())->SetRoot(root);
42 }
43
44 CPDF_IndirectObjectHolder* GetHolder() { return GetPDFDoc(); }
45};
46using CPDF_TestPdfDocument = CPDF_TestXFADocument;
47#else // PDF_ENABLE_XFA
48using CPDF_TestPdfDocument = CPDF_TestDocument;
49#endif // PDF_ENABLE_XFA
50
51class PDFDocTest : public testing::Test {
52 public:
53 struct DictObjInfo {
tsepezc3255f52016-03-25 14:52:27 -070054 uint32_t num;
Wei Li5227e572016-03-04 15:49:17 -080055 CPDF_Dictionary* obj;
56 };
57
58 void SetUp() override {
59 // We don't need page module or render module, but
60 // initialize them to keep the code sane.
Wei Li5227e572016-03-04 15:49:17 -080061 CPDF_ModuleMgr* module_mgr = CPDF_ModuleMgr::Get();
62 module_mgr->InitPageModule();
Wei Li5227e572016-03-04 15:49:17 -080063
thestigd4c34f22016-09-28 17:04:51 -070064 m_pDoc = WrapUnique(new CPDF_TestPdfDocument());
Wei Li5227e572016-03-04 15:49:17 -080065 m_pIndirectObjs = m_pDoc->GetHolder();
66 // Setup the root directory.
tsepezcd5bca42016-09-30 10:45:06 -070067 m_pRootObj.reset(new CPDF_Dictionary());
Wei Li5227e572016-03-04 15:49:17 -080068 m_pDoc->SetRoot(m_pRootObj.get());
69 }
70
thestigfd36b8f2016-07-11 10:43:48 -070071 void TearDown() override {
72 m_pRootObj.reset();
73 m_pIndirectObjs = nullptr;
74 m_pDoc.reset();
75 CPDF_ModuleMgr::Destroy();
76 }
77
Wei Li5227e572016-03-04 15:49:17 -080078 std::vector<DictObjInfo> CreateDictObjs(int num) {
79 std::vector<DictObjInfo> info;
80 for (int i = 0; i < num; ++i) {
81 // Objects created will be released by the document.
tsepezcd5bca42016-09-30 10:45:06 -070082 CPDF_Dictionary* obj = new CPDF_Dictionary();
tsepezbb577af2016-09-21 19:10:19 -070083 info.push_back({m_pIndirectObjs->AddIndirectObject(obj), obj});
Wei Li5227e572016-03-04 15:49:17 -080084 }
85 return info;
86 }
87
88 protected:
89 std::unique_ptr<CPDF_TestPdfDocument> m_pDoc;
90 CPDF_IndirectObjectHolder* m_pIndirectObjs;
91 std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>> m_pRootObj;
92};
93
94TEST_F(PDFDocTest, FindBookmark) {
95 {
96 // No bookmark information.
97 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
98 GetFPDFWideString(L"");
99 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
100
101 title = GetFPDFWideString(L"Preface");
102 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
103 }
104 {
105 // Empty bookmark tree.
tsepezcd5bca42016-09-30 10:45:06 -0700106 m_pRootObj->SetFor("Outlines", new CPDF_Dictionary());
Wei Li5227e572016-03-04 15:49:17 -0800107 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
108 GetFPDFWideString(L"");
109 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
110
111 title = GetFPDFWideString(L"Preface");
112 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
113 }
114 {
115 // Check on a regular bookmark tree.
116 auto bookmarks = CreateDictObjs(3);
117
dsinclair38fd8442016-09-15 10:15:32 -0700118 bookmarks[1].obj->SetFor("Title", new CPDF_String(L"Chapter 1"));
119 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800120 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700121 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800122 "Next", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
123
dsinclair38fd8442016-09-15 10:15:32 -0700124 bookmarks[2].obj->SetFor("Title", new CPDF_String(L"Chapter 2"));
125 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800126 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700127 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800128 "Prev", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
129
dsinclair38fd8442016-09-15 10:15:32 -0700130 bookmarks[0].obj->SetFor("Type", new CPDF_Name("Outlines"));
131 bookmarks[0].obj->SetFor("Count", new CPDF_Number(2));
132 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800133 "First", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
dsinclair38fd8442016-09-15 10:15:32 -0700134 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800135 "Last", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
136
dsinclair38fd8442016-09-15 10:15:32 -0700137 m_pRootObj->SetFor("Outlines",
138 new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
Wei Li5227e572016-03-04 15:49:17 -0800139
140 // Title with no match.
141 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
142 GetFPDFWideString(L"Chapter 3");
143 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
144
145 // Title with partial match only.
146 title = GetFPDFWideString(L"Chapter");
147 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
148
149 // Title with a match.
150 title = GetFPDFWideString(L"Chapter 2");
151 EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get()));
152
153 // Title match is case insensitive.
154 title = GetFPDFWideString(L"cHaPter 2");
155 EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get()));
156 }
157 {
158 // Circular bookmarks in depth.
159 auto bookmarks = CreateDictObjs(3);
160
dsinclair38fd8442016-09-15 10:15:32 -0700161 bookmarks[1].obj->SetFor("Title", new CPDF_String(L"Chapter 1"));
162 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800163 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700164 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800165 "First", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
166
dsinclair38fd8442016-09-15 10:15:32 -0700167 bookmarks[2].obj->SetFor("Title", new CPDF_String(L"Chapter 2"));
168 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800169 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
dsinclair38fd8442016-09-15 10:15:32 -0700170 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800171 "First", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
172
dsinclair38fd8442016-09-15 10:15:32 -0700173 bookmarks[0].obj->SetFor("Type", new CPDF_Name("Outlines"));
174 bookmarks[0].obj->SetFor("Count", new CPDF_Number(2));
175 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800176 "First", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
dsinclair38fd8442016-09-15 10:15:32 -0700177 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800178 "Last", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
179
dsinclair38fd8442016-09-15 10:15:32 -0700180 m_pRootObj->SetFor("Outlines",
181 new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
Wei Li5227e572016-03-04 15:49:17 -0800182
183 // Title with no match.
184 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
185 GetFPDFWideString(L"Chapter 3");
186 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
187
188 // Title with a match.
189 title = GetFPDFWideString(L"Chapter 2");
190 EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get()));
191 }
192 {
193 // Circular bookmarks in breadth.
194 auto bookmarks = CreateDictObjs(4);
195
dsinclair38fd8442016-09-15 10:15:32 -0700196 bookmarks[1].obj->SetFor("Title", new CPDF_String(L"Chapter 1"));
197 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800198 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700199 bookmarks[1].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800200 "Next", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
201
dsinclair38fd8442016-09-15 10:15:32 -0700202 bookmarks[2].obj->SetFor("Title", new CPDF_String(L"Chapter 2"));
203 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800204 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700205 bookmarks[2].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800206 "Next", new CPDF_Reference(m_pIndirectObjs, bookmarks[3].num));
207
dsinclair38fd8442016-09-15 10:15:32 -0700208 bookmarks[3].obj->SetFor("Title", new CPDF_String(L"Chapter 3"));
209 bookmarks[3].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800210 "Parent", new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
dsinclair38fd8442016-09-15 10:15:32 -0700211 bookmarks[3].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800212 "Next", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
213
dsinclair38fd8442016-09-15 10:15:32 -0700214 bookmarks[0].obj->SetFor("Type", new CPDF_Name("Outlines"));
215 bookmarks[0].obj->SetFor("Count", new CPDF_Number(2));
216 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800217 "First", new CPDF_Reference(m_pIndirectObjs, bookmarks[1].num));
dsinclair38fd8442016-09-15 10:15:32 -0700218 bookmarks[0].obj->SetFor(
Wei Li5227e572016-03-04 15:49:17 -0800219 "Last", new CPDF_Reference(m_pIndirectObjs, bookmarks[2].num));
220
dsinclair38fd8442016-09-15 10:15:32 -0700221 m_pRootObj->SetFor("Outlines",
222 new CPDF_Reference(m_pIndirectObjs, bookmarks[0].num));
Wei Li5227e572016-03-04 15:49:17 -0800223
224 // Title with no match.
225 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
226 GetFPDFWideString(L"Chapter 8");
227 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
228
229 // Title with a match.
230 title = GetFPDFWideString(L"Chapter 3");
231 EXPECT_EQ(bookmarks[3].obj, FPDFBookmark_Find(m_pDoc.get(), title.get()));
232 }
233}