// Check circular bookmarks will not cause infinite loop. TEST_F(FPDFDocEmbedderTest, FindBookmarks_bug420) { // Open a file with circular bookmarks. EXPECT_TRUE(OpenDocument("bookmarks_circular.pdf")); // Try to find a title. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L"anything"); EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), title.get())); }
TEST_F(FPDFDocEmbedderTest, FindBookmarks) { // Open a file with two bookmarks. EXPECT_TRUE(OpenDocument("bookmarks.pdf")); // Find the first one, based on its known title. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L"A Good Beginning"); FPDF_BOOKMARK child = FPDFBookmark_Find(document(), title.get()); EXPECT_TRUE(child); // Check that the string matches. unsigned short buf[128]; EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf))); EXPECT_EQ(WideString(L"A Good Beginning"), WideString::FromUTF16LE(buf, 16)); // Check that it is them same as the one returned by GetFirstChild. EXPECT_EQ(child, FPDFBookmark_GetFirstChild(document(), nullptr)); // Try to find one using a non-existent title. std::unique_ptr<unsigned short, pdfium::FreeDeleter> bad_title = GetFPDFWideString(L"A BAD Beginning"); EXPECT_EQ(nullptr, FPDFBookmark_Find(document(), bad_title.get())); }
TEST_F(PDFDocTest, FindBookmark) { { // No bookmark information. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L""); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); title = GetFPDFWideString(L"Preface"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); } { // Empty bookmark tree. m_pRootObj->SetNewFor<CPDF_Dictionary>("Outlines"); std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L""); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); title = GetFPDFWideString(L"Preface"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); } { // Check on a regular bookmark tree. auto bookmarks = CreateDictObjs(3); bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1"); bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs, bookmarks[2].num); bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2"); bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[2].obj->SetNewFor<CPDF_Reference>("Prev", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines"); bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2); bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs, bookmarks[2].num); m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs, bookmarks[0].num); // Title with no match. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L"Chapter 3"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); // Title with partial match only. title = GetFPDFWideString(L"Chapter"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); // Title with a match. title = GetFPDFWideString(L"Chapter 2"); EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get())); // Title match is case insensitive. title = GetFPDFWideString(L"cHaPter 2"); EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get())); } { // Circular bookmarks in depth. auto bookmarks = CreateDictObjs(3); bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1"); bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[1].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs, bookmarks[2].num); bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2"); bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[1].num); bookmarks[2].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines"); bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2); bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs, bookmarks[2].num); m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs, bookmarks[0].num); // Title with no match. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L"Chapter 3"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); // Title with a match. title = GetFPDFWideString(L"Chapter 2"); EXPECT_EQ(bookmarks[2].obj, FPDFBookmark_Find(m_pDoc.get(), title.get())); } { // Circular bookmarks in breadth. auto bookmarks = CreateDictObjs(4); bookmarks[1].obj->SetNewFor<CPDF_String>("Title", L"Chapter 1"); bookmarks[1].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[1].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs, bookmarks[2].num); bookmarks[2].obj->SetNewFor<CPDF_String>("Title", L"Chapter 2"); bookmarks[2].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[2].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs, bookmarks[3].num); bookmarks[3].obj->SetNewFor<CPDF_String>("Title", L"Chapter 3"); bookmarks[3].obj->SetNewFor<CPDF_Reference>("Parent", m_pIndirectObjs, bookmarks[0].num); bookmarks[3].obj->SetNewFor<CPDF_Reference>("Next", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Name>("Type", "Outlines"); bookmarks[0].obj->SetNewFor<CPDF_Number>("Count", 2); bookmarks[0].obj->SetNewFor<CPDF_Reference>("First", m_pIndirectObjs, bookmarks[1].num); bookmarks[0].obj->SetNewFor<CPDF_Reference>("Last", m_pIndirectObjs, bookmarks[2].num); m_pRootObj->SetNewFor<CPDF_Reference>("Outlines", m_pIndirectObjs, bookmarks[0].num); // Title with no match. std::unique_ptr<unsigned short, pdfium::FreeDeleter> title = GetFPDFWideString(L"Chapter 8"); EXPECT_EQ(nullptr, FPDFBookmark_Find(m_pDoc.get(), title.get())); // Title with a match. title = GetFPDFWideString(L"Chapter 3"); EXPECT_EQ(bookmarks[3].obj, FPDFBookmark_Find(m_pDoc.get(), title.get())); } }
TEST_F(FPDFTextEmbeddertest, TextSearch) { EXPECT_TRUE(OpenDocument("hello_world.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); FPDF_TEXTPAGE textpage = FPDFText_LoadPage(page); EXPECT_TRUE(textpage); std::unique_ptr<unsigned short, pdfium::FreeDeleter> nope = GetFPDFWideString(L"nope"); std::unique_ptr<unsigned short, pdfium::FreeDeleter> world = GetFPDFWideString(L"world"); std::unique_ptr<unsigned short, pdfium::FreeDeleter> world_caps = GetFPDFWideString(L"WORLD"); std::unique_ptr<unsigned short, pdfium::FreeDeleter> world_substr = GetFPDFWideString(L"orld"); // No occurences of "nope" in test page. FPDF_SCHHANDLE search = FPDFText_FindStart(textpage, nope.get(), 0, 0); EXPECT_TRUE(search); EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(0, FPDFText_GetSchCount(search)); // Advancing finds nothing. EXPECT_FALSE(FPDFText_FindNext(search)); EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(0, FPDFText_GetSchCount(search)); // Retreating finds nothing. EXPECT_FALSE(FPDFText_FindPrev(search)); EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(0, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // Two occurences of "world" in test page. search = FPDFText_FindStart(textpage, world.get(), 0, 2); EXPECT_TRUE(search); // Remains not found until advanced. EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(0, FPDFText_GetSchCount(search)); // First occurence of "world" in this test page. EXPECT_TRUE(FPDFText_FindNext(search)); EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); // Last occurence of "world" in this test page. EXPECT_TRUE(FPDFText_FindNext(search)); EXPECT_EQ(24, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); // Found position unchanged when fails to advance. EXPECT_FALSE(FPDFText_FindNext(search)); EXPECT_EQ(24, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); // Back to first occurence. EXPECT_TRUE(FPDFText_FindPrev(search)); EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); // Found position unchanged when fails to retreat. EXPECT_FALSE(FPDFText_FindPrev(search)); EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // Exact search unaffected by case sensitiity and whole word flags. search = FPDFText_FindStart(textpage, world.get(), FPDF_MATCHCASE | FPDF_MATCHWHOLEWORD, 0); EXPECT_TRUE(search); EXPECT_TRUE(FPDFText_FindNext(search)); EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // Default is case-insensitive, so matching agaist caps works. search = FPDFText_FindStart(textpage, world_caps.get(), 0, 0); EXPECT_TRUE(search); EXPECT_TRUE(FPDFText_FindNext(search)); EXPECT_EQ(7, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(5, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // But can be made case sensitive, in which case this fails. search = FPDFText_FindStart(textpage, world_caps.get(), FPDF_MATCHCASE, 0); EXPECT_FALSE(FPDFText_FindNext(search)); EXPECT_EQ(0, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(0, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // Default is match anywhere within word, so matching substirng works. search = FPDFText_FindStart(textpage, world_substr.get(), 0, 0); EXPECT_TRUE(FPDFText_FindNext(search)); EXPECT_EQ(8, FPDFText_GetSchResultIndex(search)); EXPECT_EQ(4, FPDFText_GetSchCount(search)); FPDFText_FindClose(search); // But can be made to mach word boundaries, in which case this fails. search = FPDFText_FindStart(textpage, world_substr.get(), FPDF_MATCHWHOLEWORD, 0); EXPECT_FALSE(FPDFText_FindNext(search)); // TODO(tsepez): investigate strange index/count values in this state. FPDFText_FindClose(search); FPDFText_ClosePage(textpage); UnloadPage(page); }