Home | History | Annotate | Download | only in parser
      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 
     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:
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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