blob: 929c2a514305ea1bf523f5e788a6c9a78bc81fd8 [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"
dsinclairc59fa882016-11-08 06:55:40 -080011#include "core/fpdfapi/parser/cpdf_array.h"
Lei Zhang81535612018-10-09 21:15:17 +000012#include "core/fpdfapi/parser/cpdf_dictionary.h"
dsinclair488b7ad2016-10-04 11:55:50 -070013#include "core/fpdfapi/parser/cpdf_document.h"
14#include "core/fpdfapi/parser/cpdf_name.h"
dsinclairc59fa882016-11-08 06:55:40 -080015#include "core/fpdfapi/parser/cpdf_null.h"
dsinclair488b7ad2016-10-04 11:55:50 -070016#include "core/fpdfapi/parser/cpdf_number.h"
17#include "core/fpdfapi/parser/cpdf_parser.h"
18#include "core/fpdfapi/parser/cpdf_reference.h"
19#include "core/fpdfapi/parser/cpdf_string.h"
dsinclairc59fa882016-11-08 06:55:40 -080020#include "core/fpdfdoc/cpdf_dest.h"
Tom Sepeza1d34422018-04-24 20:54:41 +000021#include "fpdfsdk/cpdfsdk_helpers.h"
Tom Sepezfe06d512018-05-01 17:25:25 +000022#include "public/cpp/fpdf_scopers.h"
Wei Li5227e572016-03-04 15:49:17 -080023#include "testing/gtest/include/gtest/gtest.h"
24#include "testing/test_support.h"
tsepez36eb4bd2016-10-03 15:24:27 -070025#include "third_party/base/ptr_util.h"
Wei Li5227e572016-03-04 15:49:17 -080026
Tom Sepez55865452018-08-27 20:18:04 +000027class CPDF_TestDocument final : public CPDF_Document {
Wei Li5227e572016-03-04 15:49:17 -080028 public:
Artem Strygin20eca1e2018-06-27 18:15:10 +000029 CPDF_TestDocument() : CPDF_Document() {}
thestig931bf372016-04-26 22:24:30 -070030
Wei Li5227e572016-03-04 15:49:17 -080031 void SetRoot(CPDF_Dictionary* root) { m_pRootDict = root; }
32 CPDF_IndirectObjectHolder* GetHolder() { return this; }
33};
34
Wei Li5227e572016-03-04 15:49:17 -080035class PDFDocTest : public testing::Test {
36 public:
37 struct DictObjInfo {
tsepezc3255f52016-03-25 14:52:27 -070038 uint32_t num;
Wei Li5227e572016-03-04 15:49:17 -080039 CPDF_Dictionary* obj;
40 };
41
42 void SetUp() override {
Lei Zhang76020fc2017-05-18 15:51:20 -070043 CPDF_ModuleMgr::Get()->Init();
Tom Sepezfe06d512018-05-01 17:25:25 +000044 auto pTestDoc = pdfium::MakeUnique<CPDF_TestDocument>();
45 m_pIndirectObjs = pTestDoc->GetHolder();
Tom Sepezb8654422018-06-26 15:19:38 +000046 m_pRootObj = m_pIndirectObjs->NewIndirect<CPDF_Dictionary>();
47 pTestDoc->SetRoot(m_pRootObj.Get());
Tom Sepezfe06d512018-05-01 17:25:25 +000048 m_pDoc.reset(FPDFDocumentFromCPDFDocument(pTestDoc.release()));
Wei Li5227e572016-03-04 15:49:17 -080049 }
50
thestigfd36b8f2016-07-11 10:43:48 -070051 void TearDown() override {
Tom Sepezb8654422018-06-26 15:19:38 +000052 m_pRootObj = nullptr;
thestigfd36b8f2016-07-11 10:43:48 -070053 m_pIndirectObjs = nullptr;
54 m_pDoc.reset();
55 CPDF_ModuleMgr::Destroy();
56 }
57
Wei Li5227e572016-03-04 15:49:17 -080058 std::vector<DictObjInfo> CreateDictObjs(int num) {
59 std::vector<DictObjInfo> info;
60 for (int i = 0; i < num; ++i) {
61 // Objects created will be released by the document.
tsepez70c4afd2016-11-15 11:33:44 -080062 CPDF_Dictionary* obj = m_pIndirectObjs->NewIndirect<CPDF_Dictionary>();
63 info.push_back({obj->GetObjNum(), obj});
Wei Li5227e572016-03-04 15:49:17 -080064 }
65 return info;
66 }
67
68 protected:
Tom Sepezfe06d512018-05-01 17:25:25 +000069 ScopedFPDFDocument m_pDoc;
Dan Sinclairaee0db02017-09-21 16:53:58 -040070 UnownedPtr<CPDF_IndirectObjectHolder> m_pIndirectObjs;
Tom Sepezb8654422018-06-26 15:19:38 +000071 UnownedPtr<CPDF_Dictionary> m_pRootObj;
Wei Li5227e572016-03-04 15:49:17 -080072};
73
74TEST_F(PDFDocTest, FindBookmark) {
75 {
76 // No bookmark information.
77 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
78 GetFPDFWideString(L"");
79 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
80
81 title = GetFPDFWideString(L"Preface");
82 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
83 }
84 {
85 // Empty bookmark tree.
tsepez0e606b52016-11-18 16:22:41 -080086 m_pRootObj->SetNewFor<CPDF_Dictionary>("Outlines");
Wei Li5227e572016-03-04 15:49:17 -080087 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
88 GetFPDFWideString(L"");
89 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
90
91 title = GetFPDFWideString(L"Preface");
92 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
93 }
94 {
95 // Check on a regular bookmark tree.
96 auto bookmarks = CreateDictObjs(3);
97
tsepez0e606b52016-11-18 16:22:41 -080098 bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
Tom Sepezd0409af2017-05-25 15:53:57 -070099 bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800100 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700101 bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800102 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800103
tsepez0e606b52016-11-18 16:22:41 -0800104 bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
Tom Sepezd0409af2017-05-25 15:53:57 -0700105 bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800106 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700107 bookmarks[2].obj->SetNewFor<CPDF_Reference>("Prev", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800108 bookmarks[1].num);
Wei Li5227e572016-03-04 15:49:17 -0800109
tsepez0e606b52016-11-18 16:22:41 -0800110 bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
111 bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
Tom Sepezd0409af2017-05-25 15:53:57 -0700112 bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800113 bookmarks[1].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700114 bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800115 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800116
Tom Sepezd0409af2017-05-25 15:53:57 -0700117 m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800118 bookmarks[0].num);
Wei Li5227e572016-03-04 15:49:17 -0800119
120 // Title with no match.
121 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
122 GetFPDFWideString(L"Chapter 3");
123 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
124
125 // Title with partial match only.
126 title = GetFPDFWideString(L"Chapter");
127 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
128
129 // Title with a match.
130 title = GetFPDFWideString(L"Chapter 2");
Tom Sepez525147a2018-05-03 17:19:53 +0000131 EXPECT_EQ(FPDFBookmarkFromCPDFDictionary(bookmarks[2].obj),
132 FPDFBookmark_Find(m_pDoc.get(), title.get()));
Wei Li5227e572016-03-04 15:49:17 -0800133
134 // Title match is case insensitive.
135 title = GetFPDFWideString(L"cHaPter 2");
Tom Sepez525147a2018-05-03 17:19:53 +0000136 EXPECT_EQ(FPDFBookmarkFromCPDFDictionary(bookmarks[2].obj),
137 FPDFBookmark_Find(m_pDoc.get(), title.get()));
Wei Li5227e572016-03-04 15:49:17 -0800138 }
139 {
140 // Circular bookmarks in depth.
141 auto bookmarks = CreateDictObjs(3);
142
tsepez0e606b52016-11-18 16:22:41 -0800143 bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
Tom Sepezd0409af2017-05-25 15:53:57 -0700144 bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800145 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700146 bookmarks[1].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800147 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800148
tsepez0e606b52016-11-18 16:22:41 -0800149 bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
Tom Sepezd0409af2017-05-25 15:53:57 -0700150 bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800151 bookmarks[1].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700152 bookmarks[2].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800153 bookmarks[1].num);
Wei Li5227e572016-03-04 15:49:17 -0800154
tsepez0e606b52016-11-18 16:22:41 -0800155 bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
156 bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
Tom Sepezd0409af2017-05-25 15:53:57 -0700157 bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800158 bookmarks[1].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700159 bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800160 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800161
Tom Sepezd0409af2017-05-25 15:53:57 -0700162 m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800163 bookmarks[0].num);
Wei Li5227e572016-03-04 15:49:17 -0800164
165 // Title with no match.
166 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
167 GetFPDFWideString(L"Chapter 3");
168 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
169
170 // Title with a match.
171 title = GetFPDFWideString(L"Chapter 2");
Tom Sepez525147a2018-05-03 17:19:53 +0000172 EXPECT_EQ(FPDFBookmarkFromCPDFDictionary(bookmarks[2].obj),
173 FPDFBookmark_Find(m_pDoc.get(), title.get()));
Wei Li5227e572016-03-04 15:49:17 -0800174 }
175 {
176 // Circular bookmarks in breadth.
177 auto bookmarks = CreateDictObjs(4);
178
tsepez0e606b52016-11-18 16:22:41 -0800179 bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1");
Tom Sepezd0409af2017-05-25 15:53:57 -0700180 bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800181 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700182 bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800183 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800184
tsepez0e606b52016-11-18 16:22:41 -0800185 bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2");
Tom Sepezd0409af2017-05-25 15:53:57 -0700186 bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800187 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700188 bookmarks[2].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800189 bookmarks[3].num);
Wei Li5227e572016-03-04 15:49:17 -0800190
tsepez0e606b52016-11-18 16:22:41 -0800191 bookmarks[3].obj->SetNewFor<CPDF_String>("Title", L"Chapter 3");
Tom Sepezd0409af2017-05-25 15:53:57 -0700192 bookmarks[3].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800193 bookmarks[0].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700194 bookmarks[3].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800195 bookmarks[1].num);
Wei Li5227e572016-03-04 15:49:17 -0800196
tsepez0e606b52016-11-18 16:22:41 -0800197 bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines");
198 bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2);
Tom Sepezd0409af2017-05-25 15:53:57 -0700199 bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800200 bookmarks[1].num);
Tom Sepezd0409af2017-05-25 15:53:57 -0700201 bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800202 bookmarks[2].num);
Wei Li5227e572016-03-04 15:49:17 -0800203
Tom Sepezd0409af2017-05-25 15:53:57 -0700204 m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs.Get(),
tsepez0e606b52016-11-18 16:22:41 -0800205 bookmarks[0].num);
Wei Li5227e572016-03-04 15:49:17 -0800206
207 // Title with no match.
208 std::unique_ptr<unsigned short, pdfium::FreeDeleter> title =
209 GetFPDFWideString(L"Chapter 8");
210 EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get()));
211
212 // Title with a match.
213 title = GetFPDFWideString(L"Chapter 3");
Tom Sepez525147a2018-05-03 17:19:53 +0000214 EXPECT_EQ(FPDFBookmarkFromCPDFDictionary(bookmarks[3].obj),
215 FPDFBookmark_Find(m_pDoc.get(), title.get()));
Wei Li5227e572016-03-04 15:49:17 -0800216 }
217}
dsinclairc59fa882016-11-08 06:55:40 -0800218
219TEST_F(PDFDocTest, GetLocationInPage) {
220 auto array = pdfium::MakeUnique<CPDF_Array>();
tsepez8a3aa452016-11-16 12:26:06 -0800221 array->AddNew<CPDF_Number>(0); // Page Index.
222 array->AddNew<CPDF_Name>("XYZ");
223 array->AddNew<CPDF_Number>(4); // X
224 array->AddNew<CPDF_Number>(5); // Y
225 array->AddNew<CPDF_Number>(6); // Zoom.
dsinclairc59fa882016-11-08 06:55:40 -0800226
227 FPDF_BOOL hasX;
228 FPDF_BOOL hasY;
229 FPDF_BOOL hasZoom;
230 FS_FLOAT x;
231 FS_FLOAT y;
232 FS_FLOAT zoom;
233
Tom Sepez525147a2018-05-03 17:19:53 +0000234 EXPECT_TRUE(FPDFDest_GetLocationInPage(FPDFDestFromCPDFArray(array.get()),
235 &hasX, &hasY, &hasZoom, &x, &y,
236 &zoom));
dsinclairc59fa882016-11-08 06:55:40 -0800237 EXPECT_TRUE(hasX);
238 EXPECT_TRUE(hasY);
239 EXPECT_TRUE(hasZoom);
240 EXPECT_EQ(4, x);
241 EXPECT_EQ(5, y);
242 EXPECT_EQ(6, zoom);
243
tsepez8a3aa452016-11-16 12:26:06 -0800244 array->SetNewAt<CPDF_Null>(2);
245 array->SetNewAt<CPDF_Null>(3);
246 array->SetNewAt<CPDF_Null>(4);
Tom Sepez525147a2018-05-03 17:19:53 +0000247 EXPECT_TRUE(FPDFDest_GetLocationInPage(FPDFDestFromCPDFArray(array.get()),
248 &hasX, &hasY, &hasZoom, &x, &y,
249 &zoom));
dsinclairc59fa882016-11-08 06:55:40 -0800250 EXPECT_FALSE(hasX);
251 EXPECT_FALSE(hasY);
252 EXPECT_FALSE(hasZoom);
253
254 array = pdfium::MakeUnique<CPDF_Array>();
Tom Sepez525147a2018-05-03 17:19:53 +0000255 EXPECT_FALSE(FPDFDest_GetLocationInPage(FPDFDestFromCPDFArray(array.get()),
256 &hasX, &hasY, &hasZoom, &x, &y,
257 &zoom));
dsinclairc59fa882016-11-08 06:55:40 -0800258}