• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The PDFium Authors
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 "core/fpdfdoc/cpdf_annotlist.h"
6 
7 #include <stdint.h>
8 
9 #include <initializer_list>
10 #include <memory>
11 
12 #include "constants/annotation_common.h"
13 #include "core/fpdfapi/page/cpdf_page.h"
14 #include "core/fpdfapi/page/test_with_page_module.h"
15 #include "core/fpdfapi/parser/cpdf_array.h"
16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
17 #include "core/fpdfapi/parser/cpdf_name.h"
18 #include "core/fpdfapi/parser/cpdf_string.h"
19 #include "core/fpdfapi/parser/cpdf_test_document.h"
20 #include "core/fpdfdoc/cpdf_annot.h"
21 #include "core/fxcrt/bytestring.h"
22 #include "core/fxcrt/retain_ptr.h"
23 #include "core/fxcrt/widestring.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace {
27 
28 class CPDFAnnotListTest : public TestWithPageModule {
29  public:
SetUp()30   void SetUp() override {
31     TestWithPageModule::SetUp();
32 
33     document_ = std::make_unique<CPDF_TestDocument>();
34     document_->SetRoot(pdfium::MakeRetain<CPDF_Dictionary>());
35     page_ = pdfium::MakeRetain<CPDF_Page>(
36         document_.get(), pdfium::MakeRetain<CPDF_Dictionary>());
37   }
38 
TearDown()39   void TearDown() override {
40     page_.Reset();
41     document_.reset();
42 
43     TestWithPageModule::TearDown();
44   }
45 
46  protected:
AddTextAnnotation(const ByteString & contents)47   void AddTextAnnotation(const ByteString& contents) {
48     RetainPtr<CPDF_Dictionary> annotation =
49         page_->GetOrCreateAnnotsArray()->AppendNew<CPDF_Dictionary>();
50     annotation->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Text");
51     annotation->SetNewFor<CPDF_String>(pdfium::annotation::kContents, contents,
52                                        /*bHex=*/false);
53   }
54 
55   std::unique_ptr<CPDF_TestDocument> document_;
56   RetainPtr<CPDF_Page> page_;
57 };
58 
MakeByteString(std::initializer_list<uint8_t> bytes)59 ByteString MakeByteString(std::initializer_list<uint8_t> bytes) {
60   return ByteString(std::data(bytes), std::size(bytes));
61 }
62 
GetRawContents(const CPDF_Annot * annotation)63 ByteString GetRawContents(const CPDF_Annot* annotation) {
64   return annotation->GetAnnotDict()->GetByteStringFor(
65       pdfium::annotation::kContents);
66 }
67 
GetDecodedContents(const CPDF_Annot * annotation)68 WideString GetDecodedContents(const CPDF_Annot* annotation) {
69   return annotation->GetAnnotDict()->GetUnicodeTextFor(
70       pdfium::annotation::kContents);
71 }
72 
73 }  // namespace
74 
TEST_F(CPDFAnnotListTest,CreatePopupAnnotFromPdfEncoded)75 TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromPdfEncoded) {
76   const ByteString kContents = MakeByteString({'A', 'a', 0xE4, 0xA0});
77   AddTextAnnotation(kContents);
78 
79   CPDF_AnnotList list(page_);
80 
81   ASSERT_EQ(2u, list.Count());
82   EXPECT_EQ(kContents, GetRawContents(list.GetAt(1)));
83   EXPECT_EQ(WideString::FromUTF8("Aaä€"), GetDecodedContents(list.GetAt(1)));
84 }
85 
TEST_F(CPDFAnnotListTest,CreatePopupAnnotFromUnicode)86 TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromUnicode) {
87   const ByteString kContents =
88       MakeByteString({0xFE, 0xFF, 0x00, 'A', 0x00, 'a', 0x00, 0xE4, 0x20, 0xAC,
89                       0xD8, 0x3C, 0xDF, 0xA8});
90   AddTextAnnotation(kContents);
91 
92   CPDF_AnnotList list(page_);
93 
94   ASSERT_EQ(2u, list.Count());
95   EXPECT_EQ(kContents, GetRawContents(list.GetAt(1)));
96 
97   EXPECT_EQ(WideString::FromUTF8("Aaä€��"), GetDecodedContents(list.GetAt(1)));
98 }
99 
TEST_F(CPDFAnnotListTest,CreatePopupAnnotFromEmptyPdfEncoded)100 TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyPdfEncoded) {
101   AddTextAnnotation("");
102 
103   CPDF_AnnotList list(page_);
104 
105   EXPECT_EQ(1u, list.Count());
106 }
107 
TEST_F(CPDFAnnotListTest,CreatePopupAnnotFromEmptyUnicode)108 TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyUnicode) {
109   const ByteString kContents = MakeByteString({0xFE, 0xFF});
110   AddTextAnnotation(kContents);
111 
112   CPDF_AnnotList list(page_);
113 
114   EXPECT_EQ(1u, list.Count());
115 }
116 
TEST_F(CPDFAnnotListTest,CreatePopupAnnotFromEmptyUnicodedWithEscape)117 TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyUnicodedWithEscape) {
118   const ByteString kContents =
119       MakeByteString({0xFE, 0xFF, 0x00, 0x1B, 'j', 'a', 0x00, 0x1B});
120   AddTextAnnotation(kContents);
121 
122   CPDF_AnnotList list(page_);
123 
124   EXPECT_EQ(1u, list.Count());
125 }
126