• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 "core/fpdfapi/parser/cpdf_array.h"
6 #include "core/fpdfapi/parser/cpdf_boolean.h"
7 #include "core/fpdfapi/parser/cpdf_dictionary.h"
8 #include "core/fpdfapi/parser/cpdf_name.h"
9 #include "core/fpdfapi/parser/cpdf_null.h"
10 #include "core/fpdfapi/parser/cpdf_number.h"
11 #include "core/fpdfapi/parser/cpdf_reference.h"
12 #include "core/fpdfapi/parser/cpdf_stream.h"
13 #include "core/fpdfapi/parser/cpdf_string.h"
14 
15 #include <memory>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
21 #include "core/fxcrt/fx_basic.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 namespace {
25 
TestArrayAccessors(const CPDF_Array * arr,size_t index,const char * str_val,const char * const_str_val,int int_val,float float_val,CPDF_Array * arr_val,CPDF_Dictionary * dict_val,CPDF_Stream * stream_val)26 void TestArrayAccessors(const CPDF_Array* arr,
27                         size_t index,
28                         const char* str_val,
29                         const char* const_str_val,
30                         int int_val,
31                         float float_val,
32                         CPDF_Array* arr_val,
33                         CPDF_Dictionary* dict_val,
34                         CPDF_Stream* stream_val) {
35   EXPECT_STREQ(str_val, arr->GetStringAt(index).c_str());
36   EXPECT_EQ(int_val, arr->GetIntegerAt(index));
37   EXPECT_EQ(float_val, arr->GetNumberAt(index));
38   EXPECT_EQ(float_val, arr->GetFloatAt(index));
39   EXPECT_EQ(arr_val, arr->GetArrayAt(index));
40   EXPECT_EQ(dict_val, arr->GetDictAt(index));
41   EXPECT_EQ(stream_val, arr->GetStreamAt(index));
42 }
43 
44 }  // namespace
45 
46 class PDFObjectsTest : public testing::Test {
47  public:
SetUp()48   void SetUp() override {
49     // Initialize different kinds of objects.
50     // Boolean objects.
51     CPDF_Boolean* boolean_false_obj = new CPDF_Boolean(false);
52     CPDF_Boolean* boolean_true_obj = new CPDF_Boolean(true);
53     // Number objects.
54     CPDF_Number* number_int_obj = new CPDF_Number(1245);
55     CPDF_Number* number_float_obj = new CPDF_Number(9.00345f);
56     // String objects.
57     CPDF_String* str_reg_obj = new CPDF_String(nullptr, L"A simple test");
58     CPDF_String* str_spec_obj = new CPDF_String(nullptr, L"\t\n");
59     // Name object.
60     CPDF_Name* name_obj = new CPDF_Name(nullptr, "space");
61     // Array object.
62     m_ArrayObj = new CPDF_Array;
63     m_ArrayObj->InsertNewAt<CPDF_Number>(0, 8902);
64     m_ArrayObj->InsertNewAt<CPDF_Name>(1, "address");
65     // Dictionary object.
66     m_DictObj = new CPDF_Dictionary();
67     m_DictObj->SetNewFor<CPDF_Boolean>("bool", false);
68     m_DictObj->SetNewFor<CPDF_Number>("num", 0.23f);
69     // Stream object.
70     const char content[] = "abcdefghijklmnopqrstuvwxyz";
71     size_t buf_len = FX_ArraySize(content);
72     std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len));
73     memcpy(buf.get(), content, buf_len);
74     auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>();
75     m_StreamDictObj = pNewDict.get();
76     m_StreamDictObj->SetNewFor<CPDF_String>("key1", L" test dict");
77     m_StreamDictObj->SetNewFor<CPDF_Number>("key2", -1);
78     CPDF_Stream* stream_obj =
79         new CPDF_Stream(std::move(buf), buf_len, std::move(pNewDict));
80     // Null Object.
81     CPDF_Null* null_obj = new CPDF_Null;
82     // All direct objects.
83     CPDF_Object* objs[] = {boolean_false_obj, boolean_true_obj, number_int_obj,
84                            number_float_obj,  str_reg_obj,      str_spec_obj,
85                            name_obj,          m_ArrayObj,       m_DictObj,
86                            stream_obj,        null_obj};
87     m_DirectObjTypes = {
88         CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER,
89         CPDF_Object::NUMBER,  CPDF_Object::STRING,  CPDF_Object::STRING,
90         CPDF_Object::NAME,    CPDF_Object::ARRAY,   CPDF_Object::DICTIONARY,
91         CPDF_Object::STREAM,  CPDF_Object::NULLOBJ};
92     for (size_t i = 0; i < FX_ArraySize(objs); ++i)
93       m_DirectObjs.emplace_back(objs[i]);
94 
95     // Indirect references to indirect objects.
96     m_ObjHolder = pdfium::MakeUnique<CPDF_IndirectObjectHolder>();
97     m_IndirectObjs = {m_ObjHolder->AddIndirectObject(boolean_true_obj->Clone()),
98                       m_ObjHolder->AddIndirectObject(number_int_obj->Clone()),
99                       m_ObjHolder->AddIndirectObject(str_spec_obj->Clone()),
100                       m_ObjHolder->AddIndirectObject(name_obj->Clone()),
101                       m_ObjHolder->AddIndirectObject(m_ArrayObj->Clone()),
102                       m_ObjHolder->AddIndirectObject(m_DictObj->Clone()),
103                       m_ObjHolder->AddIndirectObject(stream_obj->Clone())};
104     for (CPDF_Object* pObj : m_IndirectObjs) {
105       m_RefObjs.emplace_back(
106           new CPDF_Reference(m_ObjHolder.get(), pObj->GetObjNum()));
107     }
108   }
109 
Equal(const CPDF_Object * obj1,const CPDF_Object * obj2)110   bool Equal(const CPDF_Object* obj1, const CPDF_Object* obj2) {
111     if (obj1 == obj2)
112       return true;
113     if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType())
114       return false;
115     switch (obj1->GetType()) {
116       case CPDF_Object::BOOLEAN:
117         return obj1->GetInteger() == obj2->GetInteger();
118       case CPDF_Object::NUMBER:
119         return obj1->AsNumber()->IsInteger() == obj2->AsNumber()->IsInteger() &&
120                obj1->GetInteger() == obj2->GetInteger();
121       case CPDF_Object::STRING:
122       case CPDF_Object::NAME:
123         return obj1->GetString() == obj2->GetString();
124       case CPDF_Object::ARRAY: {
125         const CPDF_Array* array1 = obj1->AsArray();
126         const CPDF_Array* array2 = obj2->AsArray();
127         if (array1->GetCount() != array2->GetCount())
128           return false;
129         for (size_t i = 0; i < array1->GetCount(); ++i) {
130           if (!Equal(array1->GetObjectAt(i), array2->GetObjectAt(i)))
131             return false;
132         }
133         return true;
134       }
135       case CPDF_Object::DICTIONARY: {
136         const CPDF_Dictionary* dict1 = obj1->AsDictionary();
137         const CPDF_Dictionary* dict2 = obj2->AsDictionary();
138         if (dict1->GetCount() != dict2->GetCount())
139           return false;
140         for (CPDF_Dictionary::const_iterator it = dict1->begin();
141              it != dict1->end(); ++it) {
142           if (!Equal(it->second.get(), dict2->GetObjectFor(it->first)))
143             return false;
144         }
145         return true;
146       }
147       case CPDF_Object::NULLOBJ:
148         return true;
149       case CPDF_Object::STREAM: {
150         const CPDF_Stream* stream1 = obj1->AsStream();
151         const CPDF_Stream* stream2 = obj2->AsStream();
152         if (!stream1->GetDict() && !stream2->GetDict())
153           return true;
154         // Compare dictionaries.
155         if (!Equal(stream1->GetDict(), stream2->GetDict()))
156           return false;
157         // Compare sizes.
158         if (stream1->GetRawSize() != stream2->GetRawSize())
159           return false;
160         // Compare contents.
161         // Since this function is used for testing Clone(), only memory based
162         // streams need to be handled.
163         if (!stream1->IsMemoryBased() || !stream2->IsMemoryBased())
164           return false;
165         return FXSYS_memcmp(stream1->GetRawData(), stream2->GetRawData(),
166                             stream1->GetRawSize()) == 0;
167       }
168       case CPDF_Object::REFERENCE:
169         return obj1->AsReference()->GetRefObjNum() ==
170                obj2->AsReference()->GetRefObjNum();
171     }
172     return false;
173   }
174 
175  protected:
176   // m_ObjHolder needs to be declared first and destructed last since it also
177   // refers to some objects in m_DirectObjs.
178   std::unique_ptr<CPDF_IndirectObjectHolder> m_ObjHolder;
179   std::vector<std::unique_ptr<CPDF_Object>> m_DirectObjs;
180   std::vector<int> m_DirectObjTypes;
181   std::vector<std::unique_ptr<CPDF_Object>> m_RefObjs;
182   CPDF_Dictionary* m_DictObj;
183   CPDF_Dictionary* m_StreamDictObj;
184   CPDF_Array* m_ArrayObj;
185   std::vector<CPDF_Object*> m_IndirectObjs;
186 };
187 
TEST_F(PDFObjectsTest,GetString)188 TEST_F(PDFObjectsTest, GetString) {
189   const char* const direct_obj_results[] = {
190       "false", "true", "1245", "9.00345", "A simple test", "\t\n", "space",
191       "",      "",     "",     ""};
192   // Check for direct objects.
193   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
194     EXPECT_STREQ(direct_obj_results[i], m_DirectObjs[i]->GetString().c_str());
195 
196   // Check indirect references.
197   const char* const indirect_obj_results[] = {"true", "1245", "\t\n", "space",
198                                               "",     "",     ""};
199   for (size_t i = 0; i < m_RefObjs.size(); ++i) {
200     EXPECT_STREQ(indirect_obj_results[i], m_RefObjs[i]->GetString().c_str());
201   }
202 }
203 
TEST_F(PDFObjectsTest,GetUnicodeText)204 TEST_F(PDFObjectsTest, GetUnicodeText) {
205   const wchar_t* const direct_obj_results[] = {
206       L"",     L"",      L"", L"", L"A simple test",
207       L"\t\n", L"space", L"", L"", L"abcdefghijklmnopqrstuvwxyz",
208       L""};
209   // Check for direct objects.
210   for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
211     EXPECT_STREQ(direct_obj_results[i],
212                  m_DirectObjs[i]->GetUnicodeText().c_str());
213   }
214 
215   // Check indirect references.
216   for (const auto& it : m_RefObjs)
217     EXPECT_STREQ(L"", it->GetUnicodeText().c_str());
218 }
219 
TEST_F(PDFObjectsTest,GetNumber)220 TEST_F(PDFObjectsTest, GetNumber) {
221   const FX_FLOAT direct_obj_results[] = {0, 0, 1245, 9.00345f, 0, 0,
222                                          0, 0, 0,    0,        0};
223   // Check for direct objects.
224   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
225     EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetNumber());
226 
227   // Check indirect references.
228   const FX_FLOAT indirect_obj_results[] = {0, 1245, 0, 0, 0, 0, 0};
229   for (size_t i = 0; i < m_RefObjs.size(); ++i)
230     EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetNumber());
231 }
232 
TEST_F(PDFObjectsTest,GetInteger)233 TEST_F(PDFObjectsTest, GetInteger) {
234   const int direct_obj_results[] = {0, 1, 1245, 9, 0, 0, 0, 0, 0, 0, 0};
235   // Check for direct objects.
236   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
237     EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetInteger());
238 
239   // Check indirect references.
240   const int indirect_obj_results[] = {1, 1245, 0, 0, 0, 0, 0};
241   for (size_t i = 0; i < m_RefObjs.size(); ++i)
242     EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetInteger());
243 }
244 
TEST_F(PDFObjectsTest,GetDict)245 TEST_F(PDFObjectsTest, GetDict) {
246   const CPDF_Dictionary* const direct_obj_results[] = {
247       nullptr, nullptr, nullptr,   nullptr,         nullptr, nullptr,
248       nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr};
249   // Check for direct objects.
250   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
251     EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict());
252 
253   // Check indirect references.
254   const CPDF_Dictionary* const indirect_obj_results[] = {
255       nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj};
256   for (size_t i = 0; i < m_RefObjs.size(); ++i)
257     EXPECT_TRUE(Equal(indirect_obj_results[i], m_RefObjs[i]->GetDict()));
258 }
259 
TEST_F(PDFObjectsTest,GetArray)260 TEST_F(PDFObjectsTest, GetArray) {
261   const CPDF_Array* const direct_obj_results[] = {
262       nullptr, nullptr,    nullptr, nullptr, nullptr, nullptr,
263       nullptr, m_ArrayObj, nullptr, nullptr, nullptr};
264   // Check for direct objects.
265   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
266     EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->AsArray());
267 
268   // Check indirect references.
269   for (const auto& it : m_RefObjs)
270     EXPECT_EQ(nullptr, it->AsArray());
271 }
272 
TEST_F(PDFObjectsTest,Clone)273 TEST_F(PDFObjectsTest, Clone) {
274   // Check for direct objects.
275   for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
276     std::unique_ptr<CPDF_Object> obj = m_DirectObjs[i]->Clone();
277     EXPECT_TRUE(Equal(m_DirectObjs[i].get(), obj.get()));
278   }
279 
280   // Check indirect references.
281   for (const auto& it : m_RefObjs) {
282     std::unique_ptr<CPDF_Object> obj = it->Clone();
283     EXPECT_TRUE(Equal(it.get(), obj.get()));
284   }
285 }
286 
TEST_F(PDFObjectsTest,GetType)287 TEST_F(PDFObjectsTest, GetType) {
288   // Check for direct objects.
289   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
290     EXPECT_EQ(m_DirectObjTypes[i], m_DirectObjs[i]->GetType());
291 
292   // Check indirect references.
293   for (const auto& it : m_RefObjs)
294     EXPECT_EQ(CPDF_Object::REFERENCE, it->GetType());
295 }
296 
TEST_F(PDFObjectsTest,GetDirect)297 TEST_F(PDFObjectsTest, GetDirect) {
298   // Check for direct objects.
299   for (size_t i = 0; i < m_DirectObjs.size(); ++i)
300     EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->GetDirect());
301 
302   // Check indirect references.
303   for (size_t i = 0; i < m_RefObjs.size(); ++i)
304     EXPECT_EQ(m_IndirectObjs[i], m_RefObjs[i]->GetDirect());
305 }
306 
TEST_F(PDFObjectsTest,SetString)307 TEST_F(PDFObjectsTest, SetString) {
308   // Check for direct objects.
309   const char* const set_values[] = {"true",    "fake", "3.125f", "097",
310                                     "changed", "",     "NewName"};
311   const char* const expected[] = {"true",    "false", "3.125",  "97",
312                                   "changed", "",      "NewName"};
313   for (size_t i = 0; i < FX_ArraySize(set_values); ++i) {
314     m_DirectObjs[i]->SetString(set_values[i]);
315     EXPECT_STREQ(expected[i], m_DirectObjs[i]->GetString().c_str());
316   }
317 }
318 
TEST_F(PDFObjectsTest,IsTypeAndAsType)319 TEST_F(PDFObjectsTest, IsTypeAndAsType) {
320   // Check for direct objects.
321   for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
322     if (m_DirectObjTypes[i] == CPDF_Object::ARRAY) {
323       EXPECT_TRUE(m_DirectObjs[i]->IsArray());
324       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsArray());
325     } else {
326       EXPECT_FALSE(m_DirectObjs[i]->IsArray());
327       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsArray());
328     }
329 
330     if (m_DirectObjTypes[i] == CPDF_Object::BOOLEAN) {
331       EXPECT_TRUE(m_DirectObjs[i]->IsBoolean());
332       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsBoolean());
333     } else {
334       EXPECT_FALSE(m_DirectObjs[i]->IsBoolean());
335       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsBoolean());
336     }
337 
338     if (m_DirectObjTypes[i] == CPDF_Object::NAME) {
339       EXPECT_TRUE(m_DirectObjs[i]->IsName());
340       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsName());
341     } else {
342       EXPECT_FALSE(m_DirectObjs[i]->IsName());
343       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsName());
344     }
345 
346     if (m_DirectObjTypes[i] == CPDF_Object::NUMBER) {
347       EXPECT_TRUE(m_DirectObjs[i]->IsNumber());
348       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsNumber());
349     } else {
350       EXPECT_FALSE(m_DirectObjs[i]->IsNumber());
351       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsNumber());
352     }
353 
354     if (m_DirectObjTypes[i] == CPDF_Object::STRING) {
355       EXPECT_TRUE(m_DirectObjs[i]->IsString());
356       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsString());
357     } else {
358       EXPECT_FALSE(m_DirectObjs[i]->IsString());
359       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsString());
360     }
361 
362     if (m_DirectObjTypes[i] == CPDF_Object::DICTIONARY) {
363       EXPECT_TRUE(m_DirectObjs[i]->IsDictionary());
364       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsDictionary());
365     } else {
366       EXPECT_FALSE(m_DirectObjs[i]->IsDictionary());
367       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsDictionary());
368     }
369 
370     if (m_DirectObjTypes[i] == CPDF_Object::STREAM) {
371       EXPECT_TRUE(m_DirectObjs[i]->IsStream());
372       EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsStream());
373     } else {
374       EXPECT_FALSE(m_DirectObjs[i]->IsStream());
375       EXPECT_EQ(nullptr, m_DirectObjs[i]->AsStream());
376     }
377 
378     EXPECT_FALSE(m_DirectObjs[i]->IsReference());
379     EXPECT_EQ(nullptr, m_DirectObjs[i]->AsReference());
380   }
381   // Check indirect references.
382   for (size_t i = 0; i < m_RefObjs.size(); ++i) {
383     EXPECT_TRUE(m_RefObjs[i]->IsReference());
384     EXPECT_EQ(m_RefObjs[i].get(), m_RefObjs[i]->AsReference());
385   }
386 }
387 
TEST(PDFArrayTest,GetMatrix)388 TEST(PDFArrayTest, GetMatrix) {
389   float elems[][6] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
390                       {1, 2, 3, 4, 5, 6},
391                       {2.3f, 4.05f, 3, -2, -3, 0.0f},
392                       {0.05f, 0.1f, 0.56f, 0.67f, 1.34f, 99.9f}};
393   for (size_t i = 0; i < FX_ArraySize(elems); ++i) {
394     auto arr = pdfium::MakeUnique<CPDF_Array>();
395     CFX_Matrix matrix(elems[i][0], elems[i][1], elems[i][2], elems[i][3],
396                       elems[i][4], elems[i][5]);
397     for (size_t j = 0; j < 6; ++j)
398       arr->AddNew<CPDF_Number>(elems[i][j]);
399     CFX_Matrix arr_matrix = arr->GetMatrix();
400     EXPECT_EQ(matrix.a, arr_matrix.a);
401     EXPECT_EQ(matrix.b, arr_matrix.b);
402     EXPECT_EQ(matrix.c, arr_matrix.c);
403     EXPECT_EQ(matrix.d, arr_matrix.d);
404     EXPECT_EQ(matrix.e, arr_matrix.e);
405     EXPECT_EQ(matrix.f, arr_matrix.f);
406   }
407 }
408 
TEST(PDFArrayTest,GetRect)409 TEST(PDFArrayTest, GetRect) {
410   float elems[][4] = {{0.0f, 0.0f, 0.0f, 0.0f},
411                       {1, 2, 5, 6},
412                       {2.3f, 4.05f, -3, 0.0f},
413                       {0.05f, 0.1f, 1.34f, 99.9f}};
414   for (size_t i = 0; i < FX_ArraySize(elems); ++i) {
415     auto arr = pdfium::MakeUnique<CPDF_Array>();
416     CFX_FloatRect rect(elems[i]);
417     for (size_t j = 0; j < 4; ++j)
418       arr->AddNew<CPDF_Number>(elems[i][j]);
419     CFX_FloatRect arr_rect = arr->GetRect();
420     EXPECT_EQ(rect.left, arr_rect.left);
421     EXPECT_EQ(rect.right, arr_rect.right);
422     EXPECT_EQ(rect.bottom, arr_rect.bottom);
423     EXPECT_EQ(rect.top, arr_rect.top);
424   }
425 }
426 
TEST(PDFArrayTest,GetTypeAt)427 TEST(PDFArrayTest, GetTypeAt) {
428   {
429     // Boolean array.
430     const bool vals[] = {true, false, false, true, true};
431     auto arr = pdfium::MakeUnique<CPDF_Array>();
432     for (size_t i = 0; i < FX_ArraySize(vals); ++i)
433       arr->InsertNewAt<CPDF_Boolean>(i, vals[i]);
434     for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
435       TestArrayAccessors(arr.get(), i,                // Array and index.
436                          vals[i] ? "true" : "false",  // String value.
437                          nullptr,                     // Const string value.
438                          vals[i] ? 1 : 0,             // Integer value.
439                          0,                           // Float value.
440                          nullptr,                     // Array value.
441                          nullptr,                     // Dictionary value.
442                          nullptr);                    // Stream value.
443     }
444   }
445   {
446     // Integer array.
447     const int vals[] = {10, 0, -345, 2089345456, -1000000000, 567, 93658767};
448     auto arr = pdfium::MakeUnique<CPDF_Array>();
449     for (size_t i = 0; i < FX_ArraySize(vals); ++i)
450       arr->InsertNewAt<CPDF_Number>(i, vals[i]);
451     for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
452       char buf[33];
453       TestArrayAccessors(arr.get(), i,                  // Array and index.
454                          FXSYS_itoa(vals[i], buf, 10),  // String value.
455                          nullptr,                       // Const string value.
456                          vals[i],                       // Integer value.
457                          vals[i],                       // Float value.
458                          nullptr,                       // Array value.
459                          nullptr,                       // Dictionary value.
460                          nullptr);                      // Stream value.
461     }
462   }
463   {
464     // Float array.
465     const float vals[] = {0.0f,    0,     10,    10.0f,   0.0345f,
466                           897.34f, -2.5f, -1.0f, -345.0f, -0.0f};
467     const char* const expected_str[] = {
468         "0", "0", "10", "10", "0.0345", "897.34", "-2.5", "-1", "-345", "0"};
469     auto arr = pdfium::MakeUnique<CPDF_Array>();
470     for (size_t i = 0; i < FX_ArraySize(vals); ++i)
471       arr->InsertNewAt<CPDF_Number>(i, vals[i]);
472     for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
473       TestArrayAccessors(arr.get(), i,     // Array and index.
474                          expected_str[i],  // String value.
475                          nullptr,          // Const string value.
476                          vals[i],          // Integer value.
477                          vals[i],          // Float value.
478                          nullptr,          // Array value.
479                          nullptr,          // Dictionary value.
480                          nullptr);         // Stream value.
481     }
482   }
483   {
484     // String and name array
485     const char* const vals[] = {"this", "adsde$%^", "\r\t",           "\"012",
486                                 ".",    "EYREW",    "It is a joke :)"};
487     std::unique_ptr<CPDF_Array> string_array(new CPDF_Array);
488     std::unique_ptr<CPDF_Array> name_array(new CPDF_Array);
489     for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
490       string_array->InsertNewAt<CPDF_String>(i, vals[i], false);
491       name_array->InsertNewAt<CPDF_Name>(i, vals[i]);
492     }
493     for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
494       TestArrayAccessors(string_array.get(), i,  // Array and index.
495                          vals[i],                // String value.
496                          vals[i],                // Const string value.
497                          0,                      // Integer value.
498                          0,                      // Float value.
499                          nullptr,                // Array value.
500                          nullptr,                // Dictionary value.
501                          nullptr);               // Stream value.
502       TestArrayAccessors(name_array.get(), i,    // Array and index.
503                          vals[i],                // String value.
504                          vals[i],                // Const string value.
505                          0,                      // Integer value.
506                          0,                      // Float value.
507                          nullptr,                // Array value.
508                          nullptr,                // Dictionary value.
509                          nullptr);               // Stream value.
510     }
511   }
512   {
513     // Null element array.
514     auto arr = pdfium::MakeUnique<CPDF_Array>();
515     for (size_t i = 0; i < 3; ++i)
516       arr->InsertNewAt<CPDF_Null>(i);
517     for (size_t i = 0; i < 3; ++i) {
518       TestArrayAccessors(arr.get(), i,  // Array and index.
519                          "",            // String value.
520                          nullptr,       // Const string value.
521                          0,             // Integer value.
522                          0,             // Float value.
523                          nullptr,       // Array value.
524                          nullptr,       // Dictionary value.
525                          nullptr);      // Stream value.
526     }
527   }
528   {
529     // Array of array.
530     CPDF_Array* vals[3];
531     auto arr = pdfium::MakeUnique<CPDF_Array>();
532     for (size_t i = 0; i < 3; ++i) {
533       vals[i] = arr->AddNew<CPDF_Array>();
534       for (size_t j = 0; j < 3; ++j) {
535         int value = j + 100;
536         vals[i]->InsertNewAt<CPDF_Number>(i, value);
537       }
538     }
539     for (size_t i = 0; i < 3; ++i) {
540       TestArrayAccessors(arr.get(), i,  // Array and index.
541                          "",            // String value.
542                          nullptr,       // Const string value.
543                          0,             // Integer value.
544                          0,             // Float value.
545                          vals[i],       // Array value.
546                          nullptr,       // Dictionary value.
547                          nullptr);      // Stream value.
548     }
549   }
550   {
551     // Dictionary array.
552     CPDF_Dictionary* vals[3];
553     auto arr = pdfium::MakeUnique<CPDF_Array>();
554     for (size_t i = 0; i < 3; ++i) {
555       vals[i] = arr->AddNew<CPDF_Dictionary>();
556       for (size_t j = 0; j < 3; ++j) {
557         std::string key("key");
558         char buf[33];
559         key.append(FXSYS_itoa(j, buf, 10));
560         int value = j + 200;
561         vals[i]->SetNewFor<CPDF_Number>(key.c_str(), value);
562       }
563     }
564     for (size_t i = 0; i < 3; ++i) {
565       TestArrayAccessors(arr.get(), i,  // Array and index.
566                          "",            // String value.
567                          nullptr,       // Const string value.
568                          0,             // Integer value.
569                          0,             // Float value.
570                          nullptr,       // Array value.
571                          vals[i],       // Dictionary value.
572                          nullptr);      // Stream value.
573     }
574   }
575   {
576     // Stream array.
577     CPDF_Dictionary* vals[3];
578     CPDF_Stream* stream_vals[3];
579     auto arr = pdfium::MakeUnique<CPDF_Array>();
580     for (size_t i = 0; i < 3; ++i) {
581       vals[i] = new CPDF_Dictionary();
582       for (size_t j = 0; j < 3; ++j) {
583         std::string key("key");
584         char buf[33];
585         key.append(FXSYS_itoa(j, buf, 10));
586         int value = j + 200;
587         vals[i]->SetNewFor<CPDF_Number>(key.c_str(), value);
588       }
589       uint8_t content[] = "content: this is a stream";
590       size_t data_size = FX_ArraySize(content);
591       std::unique_ptr<uint8_t, FxFreeDeleter> data(
592           FX_Alloc(uint8_t, data_size));
593       memcpy(data.get(), content, data_size);
594       stream_vals[i] = arr->AddNew<CPDF_Stream>(std::move(data), data_size,
595                                                 pdfium::WrapUnique(vals[i]));
596     }
597     for (size_t i = 0; i < 3; ++i) {
598       TestArrayAccessors(arr.get(), i,     // Array and index.
599                          "",               // String value.
600                          nullptr,          // Const string value.
601                          0,                // Integer value.
602                          0,                // Float value.
603                          nullptr,          // Array value.
604                          vals[i],          // Dictionary value.
605                          stream_vals[i]);  // Stream value.
606     }
607   }
608   {
609     // Mixed array.
610     auto arr = pdfium::MakeUnique<CPDF_Array>();
611     arr->InsertNewAt<CPDF_Boolean>(0, true);
612     arr->InsertNewAt<CPDF_Boolean>(1, false);
613     arr->InsertNewAt<CPDF_Number>(2, 0);
614     arr->InsertNewAt<CPDF_Number>(3, -1234);
615     arr->InsertNewAt<CPDF_Number>(4, 2345.0f);
616     arr->InsertNewAt<CPDF_Number>(5, 0.05f);
617     arr->InsertNewAt<CPDF_String>(6, "", false);
618     arr->InsertNewAt<CPDF_String>(7, "It is a test!", false);
619     arr->InsertNewAt<CPDF_Name>(8, "NAME");
620     arr->InsertNewAt<CPDF_Name>(9, "test");
621     arr->InsertNewAt<CPDF_Null>(10);
622 
623     CPDF_Array* arr_val = arr->InsertNewAt<CPDF_Array>(11);
624     arr_val->AddNew<CPDF_Number>(1);
625     arr_val->AddNew<CPDF_Number>(2);
626 
627     CPDF_Dictionary* dict_val = arr->InsertNewAt<CPDF_Dictionary>(12);
628     dict_val->SetNewFor<CPDF_String>("key1", "Linda", false);
629     dict_val->SetNewFor<CPDF_String>("key2", "Zoe", false);
630 
631     CPDF_Dictionary* stream_dict = new CPDF_Dictionary();
632     stream_dict->SetNewFor<CPDF_String>("key1", "John", false);
633     stream_dict->SetNewFor<CPDF_String>("key2", "King", false);
634     uint8_t data[] = "A stream for test";
635     // The data buffer will be owned by stream object, so it needs to be
636     // dynamically allocated.
637     size_t buf_size = sizeof(data);
638     std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_size));
639     memcpy(buf.get(), data, buf_size);
640     CPDF_Stream* stream_val = arr->InsertNewAt<CPDF_Stream>(
641         13, std::move(buf), buf_size, pdfium::WrapUnique(stream_dict));
642     const char* const expected_str[] = {
643         "true",          "false", "0",    "-1234", "2345", "0.05", "",
644         "It is a test!", "NAME",  "test", "",      "",     "",     ""};
645     const int expected_int[] = {1, 0, 0, -1234, 2345, 0, 0,
646                                 0, 0, 0, 0,     0,    0, 0};
647     const float expected_float[] = {0, 0, 0, -1234, 2345, 0.05f, 0,
648                                     0, 0, 0, 0,     0,    0,     0};
649     for (size_t i = 0; i < arr->GetCount(); ++i) {
650       EXPECT_STREQ(expected_str[i], arr->GetStringAt(i).c_str());
651       EXPECT_EQ(expected_int[i], arr->GetIntegerAt(i));
652       EXPECT_EQ(expected_float[i], arr->GetNumberAt(i));
653       EXPECT_EQ(expected_float[i], arr->GetFloatAt(i));
654       if (i == 11)
655         EXPECT_EQ(arr_val, arr->GetArrayAt(i));
656       else
657         EXPECT_EQ(nullptr, arr->GetArrayAt(i));
658       if (i == 13) {
659         EXPECT_EQ(stream_dict, arr->GetDictAt(i));
660         EXPECT_EQ(stream_val, arr->GetStreamAt(i));
661       } else {
662         EXPECT_EQ(nullptr, arr->GetStreamAt(i));
663         if (i == 12)
664           EXPECT_EQ(dict_val, arr->GetDictAt(i));
665         else
666           EXPECT_EQ(nullptr, arr->GetDictAt(i));
667       }
668     }
669   }
670 }
671 
TEST(PDFArrayTest,AddNumber)672 TEST(PDFArrayTest, AddNumber) {
673   float vals[] = {1.0f,         -1.0f, 0,    0.456734f,
674                   12345.54321f, 0.5f,  1000, 0.000045f};
675   auto arr = pdfium::MakeUnique<CPDF_Array>();
676   for (size_t i = 0; i < FX_ArraySize(vals); ++i)
677     arr->AddNew<CPDF_Number>(vals[i]);
678   for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
679     EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType());
680     EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber());
681   }
682 }
683 
TEST(PDFArrayTest,AddInteger)684 TEST(PDFArrayTest, AddInteger) {
685   int vals[] = {0, 1, 934435456, 876, 10000, -1, -24354656, -100};
686   auto arr = pdfium::MakeUnique<CPDF_Array>();
687   for (size_t i = 0; i < FX_ArraySize(vals); ++i)
688     arr->AddNew<CPDF_Number>(vals[i]);
689   for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
690     EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType());
691     EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber());
692   }
693 }
694 
TEST(PDFArrayTest,AddStringAndName)695 TEST(PDFArrayTest, AddStringAndName) {
696   const char* vals[] = {"",        "a", "ehjhRIOYTTFdfcdnv",  "122323",
697                         "$#%^&**", " ", "This is a test.\r\n"};
698   std::unique_ptr<CPDF_Array> string_array(new CPDF_Array);
699   std::unique_ptr<CPDF_Array> name_array(new CPDF_Array);
700   for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
701     string_array->AddNew<CPDF_String>(vals[i], false);
702     name_array->AddNew<CPDF_Name>(vals[i]);
703   }
704   for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
705     EXPECT_EQ(CPDF_Object::STRING, string_array->GetObjectAt(i)->GetType());
706     EXPECT_STREQ(vals[i], string_array->GetObjectAt(i)->GetString().c_str());
707     EXPECT_EQ(CPDF_Object::NAME, name_array->GetObjectAt(i)->GetType());
708     EXPECT_STREQ(vals[i], name_array->GetObjectAt(i)->GetString().c_str());
709   }
710 }
711 
TEST(PDFArrayTest,AddReferenceAndGetObjectAt)712 TEST(PDFArrayTest, AddReferenceAndGetObjectAt) {
713   std::unique_ptr<CPDF_IndirectObjectHolder> holder(
714       new CPDF_IndirectObjectHolder());
715   CPDF_Boolean* boolean_obj = new CPDF_Boolean(true);
716   CPDF_Number* int_obj = new CPDF_Number(-1234);
717   CPDF_Number* float_obj = new CPDF_Number(2345.089f);
718   CPDF_String* str_obj =
719       new CPDF_String(nullptr, "Adsfdsf 343434 %&&*\n", false);
720   CPDF_Name* name_obj = new CPDF_Name(nullptr, "Title:");
721   CPDF_Null* null_obj = new CPDF_Null();
722   CPDF_Object* indirect_objs[] = {boolean_obj, int_obj,  float_obj,
723                                   str_obj,     name_obj, null_obj};
724   unsigned int obj_nums[] = {2, 4, 7, 2345, 799887, 1};
725   auto arr = pdfium::MakeUnique<CPDF_Array>();
726   std::unique_ptr<CPDF_Array> arr1(new CPDF_Array);
727   // Create two arrays of references by different AddReference() APIs.
728   for (size_t i = 0; i < FX_ArraySize(indirect_objs); ++i) {
729     holder->ReplaceIndirectObjectIfHigherGeneration(
730         obj_nums[i], pdfium::WrapUnique<CPDF_Object>(indirect_objs[i]));
731     arr->AddNew<CPDF_Reference>(holder.get(), obj_nums[i]);
732     arr1->AddNew<CPDF_Reference>(holder.get(), indirect_objs[i]->GetObjNum());
733   }
734   // Check indirect objects.
735   for (size_t i = 0; i < FX_ArraySize(obj_nums); ++i)
736     EXPECT_EQ(indirect_objs[i], holder->GetOrParseIndirectObject(obj_nums[i]));
737   // Check arrays.
738   EXPECT_EQ(arr->GetCount(), arr1->GetCount());
739   for (size_t i = 0; i < arr->GetCount(); ++i) {
740     EXPECT_EQ(CPDF_Object::REFERENCE, arr->GetObjectAt(i)->GetType());
741     EXPECT_EQ(indirect_objs[i], arr->GetObjectAt(i)->GetDirect());
742     EXPECT_EQ(indirect_objs[i], arr->GetDirectObjectAt(i));
743     EXPECT_EQ(CPDF_Object::REFERENCE, arr1->GetObjectAt(i)->GetType());
744     EXPECT_EQ(indirect_objs[i], arr1->GetObjectAt(i)->GetDirect());
745     EXPECT_EQ(indirect_objs[i], arr1->GetDirectObjectAt(i));
746   }
747 }
748 
TEST(PDFArrayTest,CloneDirectObject)749 TEST(PDFArrayTest, CloneDirectObject) {
750   CPDF_IndirectObjectHolder objects_holder;
751   std::unique_ptr<CPDF_Array> array(new CPDF_Array);
752   array->AddNew<CPDF_Reference>(&objects_holder, 1234);
753   ASSERT_EQ(1U, array->GetCount());
754   CPDF_Object* obj = array->GetObjectAt(0);
755   ASSERT_TRUE(obj);
756   EXPECT_TRUE(obj->IsReference());
757 
758   std::unique_ptr<CPDF_Object> cloned_array_object = array->CloneDirectObject();
759   ASSERT_TRUE(cloned_array_object);
760   ASSERT_TRUE(cloned_array_object->IsArray());
761 
762   std::unique_ptr<CPDF_Array> cloned_array =
763       ToArray(std::move(cloned_array_object));
764   ASSERT_EQ(1U, cloned_array->GetCount());
765   CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0);
766   EXPECT_FALSE(cloned_obj);
767 }
768 
TEST(PDFArrayTest,ConvertIndirect)769 TEST(PDFArrayTest, ConvertIndirect) {
770   CPDF_IndirectObjectHolder objects_holder;
771   auto array = pdfium::MakeUnique<CPDF_Array>();
772   CPDF_Object* pObj = array->AddNew<CPDF_Number>(42);
773   array->ConvertToIndirectObjectAt(0, &objects_holder);
774   CPDF_Object* pRef = array->GetObjectAt(0);
775   CPDF_Object* pNum = array->GetDirectObjectAt(0);
776   EXPECT_TRUE(pRef->IsReference());
777   EXPECT_TRUE(pNum->IsNumber());
778   EXPECT_NE(pObj, pRef);
779   EXPECT_EQ(pObj, pNum);
780   EXPECT_EQ(42, array->GetIntegerAt(0));
781 }
782 
TEST(PDFDictionaryTest,CloneDirectObject)783 TEST(PDFDictionaryTest, CloneDirectObject) {
784   CPDF_IndirectObjectHolder objects_holder;
785   std::unique_ptr<CPDF_Dictionary> dict(new CPDF_Dictionary());
786   dict->SetNewFor<CPDF_Reference>("foo", &objects_holder, 1234);
787   ASSERT_EQ(1U, dict->GetCount());
788   CPDF_Object* obj = dict->GetObjectFor("foo");
789   ASSERT_TRUE(obj);
790   EXPECT_TRUE(obj->IsReference());
791 
792   std::unique_ptr<CPDF_Object> cloned_dict_object = dict->CloneDirectObject();
793   ASSERT_TRUE(cloned_dict_object);
794   ASSERT_TRUE(cloned_dict_object->IsDictionary());
795 
796   std::unique_ptr<CPDF_Dictionary> cloned_dict =
797       ToDictionary(std::move(cloned_dict_object));
798   ASSERT_EQ(1U, cloned_dict->GetCount());
799   CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo");
800   EXPECT_FALSE(cloned_obj);
801 }
802 
TEST(PDFObjectTest,CloneCheckLoop)803 TEST(PDFObjectTest, CloneCheckLoop) {
804   {
805     // Create a dictionary/array pair with a reference loop. It takes
806     // some work to do this nowadays, in particular we need the
807     // anti-pattern pdfium::WrapUnique(arr.get()).
808     auto arr_obj = pdfium::MakeUnique<CPDF_Array>();
809     CPDF_Dictionary* dict_obj = arr_obj->InsertNewAt<CPDF_Dictionary>(0);
810     dict_obj->SetFor("arr", pdfium::WrapUnique(arr_obj.get()));
811     // Clone this object to see whether stack overflow will be triggered.
812     std::unique_ptr<CPDF_Array> cloned_array = ToArray(arr_obj->Clone());
813     // Cloned object should be the same as the original.
814     ASSERT_TRUE(cloned_array);
815     EXPECT_EQ(1u, cloned_array->GetCount());
816     CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0);
817     ASSERT_TRUE(cloned_dict);
818     ASSERT_TRUE(cloned_dict->IsDictionary());
819     // Recursively referenced object is not cloned.
820     EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr"));
821   }
822   {
823     // Create a dictionary/stream pair with a reference loop. It takes
824     // some work to do this nowadays, in particular we need the
825     // anti-pattern pdfium::WrapUnique(dict.get()).
826     auto dict_obj = pdfium::MakeUnique<CPDF_Dictionary>();
827     CPDF_Stream* stream_obj = dict_obj->SetNewFor<CPDF_Stream>(
828         "stream", nullptr, 0, pdfium::WrapUnique(dict_obj.get()));
829     // Clone this object to see whether stack overflow will be triggered.
830     std::unique_ptr<CPDF_Stream> cloned_stream = ToStream(stream_obj->Clone());
831     // Cloned object should be the same as the original.
832     ASSERT_TRUE(cloned_stream);
833     CPDF_Object* cloned_dict = cloned_stream->GetDict();
834     ASSERT_TRUE(cloned_dict);
835     ASSERT_TRUE(cloned_dict->IsDictionary());
836     // Recursively referenced object is not cloned.
837     EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("stream"));
838   }
839   {
840     CPDF_IndirectObjectHolder objects_holder;
841     // Create an object with a reference loop.
842     CPDF_Dictionary* dict_obj = objects_holder.NewIndirect<CPDF_Dictionary>();
843     std::unique_ptr<CPDF_Array> arr_obj = pdfium::MakeUnique<CPDF_Array>();
844     arr_obj->InsertNewAt<CPDF_Reference>(0, &objects_holder,
845                                          dict_obj->GetObjNum());
846     CPDF_Object* elem0 = arr_obj->GetObjectAt(0);
847     dict_obj->SetFor("arr", std::move(arr_obj));
848     EXPECT_EQ(1u, dict_obj->GetObjNum());
849     ASSERT_TRUE(elem0);
850     ASSERT_TRUE(elem0->IsReference());
851     EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum());
852     EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect());
853 
854     // Clone this object to see whether stack overflow will be triggered.
855     std::unique_ptr<CPDF_Dictionary> cloned_dict =
856         ToDictionary(dict_obj->CloneDirectObject());
857     // Cloned object should be the same as the original.
858     ASSERT_TRUE(cloned_dict);
859     CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr");
860     ASSERT_TRUE(cloned_arr);
861     ASSERT_TRUE(cloned_arr->IsArray());
862     EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount());
863     // Recursively referenced object is not cloned.
864     EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0));
865   }
866 }
867 
TEST(PDFDictionaryTest,ConvertIndirect)868 TEST(PDFDictionaryTest, ConvertIndirect) {
869   CPDF_IndirectObjectHolder objects_holder;
870   std::unique_ptr<CPDF_Dictionary> dict(new CPDF_Dictionary);
871   CPDF_Object* pObj = dict->SetNewFor<CPDF_Number>("clams", 42);
872   dict->ConvertToIndirectObjectFor("clams", &objects_holder);
873   CPDF_Object* pRef = dict->GetObjectFor("clams");
874   CPDF_Object* pNum = dict->GetDirectObjectFor("clams");
875   EXPECT_TRUE(pRef->IsReference());
876   EXPECT_TRUE(pNum->IsNumber());
877   EXPECT_NE(pObj, pRef);
878   EXPECT_EQ(pObj, pNum);
879   EXPECT_EQ(42, dict->GetIntegerFor("clams"));
880 }
881