• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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/fpdfapi/parser/cpdf_array.h"
6 
7 #include <iterator>
8 #include <memory>
9 #include <utility>
10 
11 #include "core/fpdfapi/parser/cpdf_boolean.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/cpdf_number.h"
14 #include "core/fpdfapi/parser/cpdf_reference.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
TEST(ArrayTest,GetBooleanAt)17 TEST(ArrayTest, GetBooleanAt) {
18   auto arr = pdfium::MakeRetain<CPDF_Array>();
19   arr->AppendNew<CPDF_Boolean>(true);
20   arr->AppendNew<CPDF_Boolean>(false);
21   arr->AppendNew<CPDF_Number>(100);
22   arr->AppendNew<CPDF_Number>(0);
23 
24   ASSERT_EQ(4u, arr->size());
25   EXPECT_TRUE(arr->GetBooleanAt(0, true));
26   EXPECT_TRUE(arr->GetBooleanAt(0, false));
27   EXPECT_FALSE(arr->GetBooleanAt(1, true));
28   EXPECT_FALSE(arr->GetBooleanAt(1, false));
29   EXPECT_TRUE(arr->GetBooleanAt(2, true));
30   EXPECT_FALSE(arr->GetBooleanAt(2, false));
31   EXPECT_TRUE(arr->GetBooleanAt(3, true));
32   EXPECT_FALSE(arr->GetBooleanAt(3, false));
33   EXPECT_TRUE(arr->GetBooleanAt(99, true));
34   EXPECT_FALSE(arr->GetBooleanAt(99, false));
35 }
36 
TEST(ArrayTest,RemoveAt)37 TEST(ArrayTest, RemoveAt) {
38   {
39     auto arr = pdfium::MakeRetain<CPDF_Array>();
40     for (const int elem : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
41       arr->AppendNew<CPDF_Number>(elem);
42     }
43     for (size_t i = 0; i < 3; ++i)
44       arr->RemoveAt(3);
45     constexpr std::array<int, 7> expected = {{1, 2, 3, 7, 8, 9, 10}};
46     ASSERT_EQ(expected.size(), arr->size());
47     for (size_t i = 0; i < expected.size(); ++i) {
48       EXPECT_EQ(expected[i], arr->GetIntegerAt(i));
49     }
50     arr->RemoveAt(4);
51     arr->RemoveAt(4);
52     constexpr std::array<int, 5> expected2 = {{1, 2, 3, 7, 10}};
53     ASSERT_EQ(std::size(expected2), arr->size());
54     for (size_t i = 0; i < std::size(expected2); ++i)
55       EXPECT_EQ(expected2[i], arr->GetIntegerAt(i));
56   }
57   {
58     // When the range is out of bound, RemoveAt() has no effect.
59     auto arr = pdfium::MakeRetain<CPDF_Array>();
60     for (const int elem : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
61       arr->AppendNew<CPDF_Number>(elem);
62     }
63     EXPECT_EQ(10u, arr->size());
64     arr->RemoveAt(11);
65     EXPECT_EQ(10u, arr->size());
66   }
67 }
68 
TEST(ArrayTest,Clear)69 TEST(ArrayTest, Clear) {
70   auto arr = pdfium::MakeRetain<CPDF_Array>();
71   for (const int elem : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
72     arr->AppendNew<CPDF_Number>(elem);
73   }
74   EXPECT_EQ(10u, arr->size());
75   arr->Clear();
76   EXPECT_EQ(0U, arr->size());
77 }
78 
TEST(ArrayTest,SetAtBeyond)79 TEST(ArrayTest, SetAtBeyond) {
80   auto arr = pdfium::MakeRetain<CPDF_Array>();
81   EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(0, 0));
82   EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0));
83   EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(1, 0));
84 }
85 
TEST(ArrayTest,InsertAt)86 TEST(ArrayTest, InsertAt) {
87   constexpr std::array<int, 10> elems = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
88   auto arr = pdfium::MakeRetain<CPDF_Array>();
89   for (size_t i = 0; i < std::size(elems); ++i) {
90     arr->InsertNewAt<CPDF_Number>(i, elems[i]);
91   }
92   ASSERT_EQ(std::size(elems), arr->size());
93   for (size_t i = 0; i < std::size(elems); ++i) {
94     EXPECT_EQ(elems[i], arr->GetIntegerAt(i));
95   }
96   arr->InsertNewAt<CPDF_Number>(3, 33);
97   arr->InsertNewAt<CPDF_Number>(6, 55);
98   arr->InsertNewAt<CPDF_Number>(12, 12);
99   constexpr std::array<int, 13> expected = {
100       {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}};
101   ASSERT_EQ(expected.size(), arr->size());
102   for (size_t i = 0; i < expected.size(); ++i) {
103     EXPECT_EQ(expected[i], arr->GetIntegerAt(i));
104   }
105 }
106 
TEST(ArrayTest,InsertAtBeyond)107 TEST(ArrayTest, InsertAtBeyond) {
108   auto arr = pdfium::MakeRetain<CPDF_Array>();
109   EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(1, 0));
110   EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0));
111   EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(2, 0));
112 }
113 
TEST(ArrayTest,Clone)114 TEST(ArrayTest, Clone) {
115   {
116     // Basic case.
117     constexpr std::array<int, 10> elems = {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
118     auto arr = pdfium::MakeRetain<CPDF_Array>();
119     for (size_t i = 0; i < std::size(elems); ++i) {
120       arr->InsertNewAt<CPDF_Number>(i, elems[i]);
121     }
122     RetainPtr<CPDF_Array> arr2 = ToArray(arr->Clone());
123     ASSERT_EQ(arr->size(), arr2->size());
124     for (size_t i = 0; i < std::size(elems); ++i) {
125       // Clone() always create new objects.
126       EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i));
127       EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i));
128     }
129   }
130   {
131     // Clone() with and without dereferencing reference objects.
132     static const size_t kNumOfRows = 3;
133     static const size_t kNumOfColumns = 5;
134     using ElemRow = std::array<int, kNumOfColumns>;
135     constexpr std::array<ElemRow, kNumOfRows> elems = {{
136         {{1, 2, 3, 4, 5}},
137         {{10, 9, 8, 7, 6}},
138         {{11, 12, 13, 14, 15}},
139     }};
140     auto arr = pdfium::MakeRetain<CPDF_Array>();
141     // Indirect references to indirect objects.
142     auto obj_holder = std::make_unique<CPDF_IndirectObjectHolder>();
143     for (size_t i = 0; i < kNumOfRows; ++i) {
144       auto arr_elem = pdfium::MakeRetain<CPDF_Array>();
145       for (size_t j = 0; j < kNumOfColumns; ++j) {
146         auto obj = pdfium::MakeRetain<CPDF_Number>(elems[i][j]);
147         // Starts object number from 1.
148         int obj_num = i * kNumOfColumns + j + 1;
149         obj_holder->ReplaceIndirectObjectIfHigherGeneration(obj_num,
150                                                             std::move(obj));
151         arr_elem->InsertNewAt<CPDF_Reference>(j, obj_holder.get(), obj_num);
152       }
153       arr->InsertAt(i, std::move(arr_elem));
154     }
155     ASSERT_EQ(kNumOfRows, arr->size());
156     // Not dereferencing reference objects means just creating new references
157     // instead of new copies of direct objects.
158     RetainPtr<CPDF_Array> arr1 = ToArray(arr->Clone());
159     ASSERT_EQ(arr->size(), arr1->size());
160     // Dereferencing reference objects creates new copies of direct objects.
161     RetainPtr<CPDF_Array> arr2 = ToArray(arr->CloneDirectObject());
162     ASSERT_EQ(arr->size(), arr2->size());
163     for (size_t i = 0; i < kNumOfRows; ++i) {
164       const CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray();
165       const CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray();
166       const CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray();
167       EXPECT_NE(arr_elem, arr1_elem);
168       EXPECT_NE(arr_elem, arr2_elem);
169       for (size_t j = 0; j < kNumOfColumns; ++j) {
170         auto elem_obj = arr_elem->GetObjectAt(j);
171         auto elem_obj1 = arr1_elem->GetObjectAt(j);
172         auto elem_obj2 = arr2_elem->GetObjectAt(j);
173         // Results from not deferencing reference objects.
174         EXPECT_NE(elem_obj, elem_obj1);
175         EXPECT_TRUE(elem_obj1->IsReference());
176         EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect());
177         EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger());
178         // Results from deferencing reference objects.
179         EXPECT_NE(elem_obj, elem_obj2);
180         EXPECT_TRUE(elem_obj2->IsNumber());
181         EXPECT_NE(elem_obj->GetDirect(), elem_obj2);
182         EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum());
183         EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger());
184       }
185     }
186     arr.Reset();
187     ASSERT_EQ(kNumOfRows, arr1->size());
188     for (size_t i = 0; i < kNumOfRows; ++i) {
189       for (size_t j = 0; j < kNumOfColumns; ++j) {
190         // Results from not deferencing reference objects.
191         auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j);
192         EXPECT_TRUE(elem_obj1->IsReference());
193         EXPECT_EQ(elems[i][j], elem_obj1->GetInteger());
194         // Results from deferencing reference objects.
195         EXPECT_EQ(elems[i][j],
196                   arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j));
197       }
198     }
199   }
200 }
201 
TEST(ArrayTest,Find)202 TEST(ArrayTest, Find) {
203   auto arr = pdfium::MakeRetain<CPDF_Array>();
204   auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
205   auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
206   auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
207   arr->Append(dict0);
208   arr->Append(dict1);
209 
210   std::optional<size_t> maybe_found = arr->Find(nullptr);
211   EXPECT_FALSE(maybe_found.has_value());
212 
213   maybe_found = arr->Find(dict0.Get());
214   ASSERT_TRUE(maybe_found.has_value());
215   EXPECT_EQ(0u, maybe_found.value());
216 
217   maybe_found = arr->Find(dict1.Get());
218   ASSERT_TRUE(maybe_found.has_value());
219   EXPECT_EQ(1u, maybe_found.value());
220 
221   maybe_found = arr->Find(dict2.Get());
222   EXPECT_FALSE(maybe_found.has_value());
223 }
224 
TEST(ArrayTest,Contains)225 TEST(ArrayTest, Contains) {
226   auto arr = pdfium::MakeRetain<CPDF_Array>();
227   auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
228   auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
229   auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
230   arr->Append(dict0);
231   arr->Append(dict1);
232   EXPECT_TRUE(arr->Contains(dict0.Get()));
233   EXPECT_TRUE(arr->Contains(dict1.Get()));
234   EXPECT_FALSE(arr->Contains(dict2.Get()));
235 }
236 
TEST(ArrayTest,Iterator)237 TEST(ArrayTest, Iterator) {
238   constexpr std::array<int, 10> elems = {
239       {-23, -11, 3, 455, 2345877, 0, 7895330, -12564334, 10000, -100000}};
240   auto arr = pdfium::MakeRetain<CPDF_Array>();
241   for (size_t i = 0; i < std::size(elems); ++i) {
242     arr->InsertNewAt<CPDF_Number>(i, elems[i]);
243   }
244   size_t index = 0;
245   CPDF_ArrayLocker locker(arr);
246   for (const auto& it : locker) {
247     EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger());
248   }
249   EXPECT_EQ(std::size(elems), index);
250 }
251