| OLD | NEW |
| 1 // Copyright 2016 PDFium Authors. All rights reserved. | 1 // Copyright 2016 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | 5 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" |
| 6 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" | 6 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" |
| 7 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" | 7 #include "core/fpdfapi/fpdf_parser/cpdf_dictionary.h" |
| 8 #include "core/fpdfapi/fpdf_parser/cpdf_name.h" | 8 #include "core/fpdfapi/fpdf_parser/cpdf_name.h" |
| 9 #include "core/fpdfapi/fpdf_parser/cpdf_null.h" | 9 #include "core/fpdfapi/fpdf_parser/cpdf_null.h" |
| 10 #include "core/fpdfapi/fpdf_parser/cpdf_number.h" | 10 #include "core/fpdfapi/fpdf_parser/cpdf_number.h" |
| 11 #include "core/fpdfapi/fpdf_parser/cpdf_reference.h" | 11 #include "core/fpdfapi/fpdf_parser/cpdf_reference.h" |
| 12 #include "core/fpdfapi/fpdf_parser/cpdf_stream.h" | 12 #include "core/fpdfapi/fpdf_parser/cpdf_stream.h" |
| 13 #include "core/fpdfapi/fpdf_parser/cpdf_string.h" | 13 #include "core/fpdfapi/fpdf_parser/cpdf_string.h" |
| 14 | 14 |
| 15 #include <memory> | 15 #include <memory> |
| 16 #include <string> | 16 #include <string> |
| 17 #include <vector> | 17 #include <vector> |
| 18 | 18 |
| 19 #include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" | 19 #include "core/fpdfapi/fpdf_parser/cpdf_indirect_object_holder.h" |
| 20 #include "core/fxcrt/fx_basic.h" | 20 #include "core/fxcrt/fx_basic.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>; | 25 using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>; |
| 26 using ScopedDict = | 26 using ScopedDict = |
| 27 std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>; | 27 std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>; |
| 28 using ScopedStream = std::unique_ptr<CPDF_Stream, ReleaseDeleter<CPDF_Stream>>; | |
| 29 | 28 |
| 30 void TestArrayAccessors(const CPDF_Array* arr, | 29 void TestArrayAccessors(const CPDF_Array* arr, |
| 31 size_t index, | 30 size_t index, |
| 32 const char* str_val, | 31 const char* str_val, |
| 33 const char* const_str_val, | 32 const char* const_str_val, |
| 34 int int_val, | 33 int int_val, |
| 35 float float_val, | 34 float float_val, |
| 36 CPDF_Array* arr_val, | 35 CPDF_Array* arr_val, |
| 37 CPDF_Dictionary* dict_val, | 36 CPDF_Dictionary* dict_val, |
| 38 CPDF_Stream* stream_val) { | 37 CPDF_Stream* stream_val) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 m_DirectObjTypes = { | 88 m_DirectObjTypes = { |
| 90 CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER, | 89 CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER, |
| 91 CPDF_Object::NUMBER, CPDF_Object::STRING, CPDF_Object::STRING, | 90 CPDF_Object::NUMBER, CPDF_Object::STRING, CPDF_Object::STRING, |
| 92 CPDF_Object::NAME, CPDF_Object::ARRAY, CPDF_Object::DICTIONARY, | 91 CPDF_Object::NAME, CPDF_Object::ARRAY, CPDF_Object::DICTIONARY, |
| 93 CPDF_Object::STREAM, CPDF_Object::NULLOBJ}; | 92 CPDF_Object::STREAM, CPDF_Object::NULLOBJ}; |
| 94 for (size_t i = 0; i < FX_ArraySize(objs); ++i) | 93 for (size_t i = 0; i < FX_ArraySize(objs); ++i) |
| 95 m_DirectObjs.emplace_back(objs[i]); | 94 m_DirectObjs.emplace_back(objs[i]); |
| 96 | 95 |
| 97 // Indirect references to indirect objects. | 96 // Indirect references to indirect objects. |
| 98 m_ObjHolder.reset(new CPDF_IndirectObjectHolder()); | 97 m_ObjHolder.reset(new CPDF_IndirectObjectHolder()); |
| 99 m_IndirectObjs = {boolean_true_obj->Clone(), number_int_obj->Clone(), | 98 m_IndirectObjs = {boolean_true_obj, number_int_obj, str_spec_obj, name_obj, |
| 100 str_spec_obj->Clone(), name_obj->Clone(), | 99 m_ArrayObj, m_DictObj, stream_obj}; |
| 101 m_ArrayObj->Clone(), m_DictObj->Clone(), | |
| 102 stream_obj->Clone()}; | |
| 103 for (size_t i = 0; i < m_IndirectObjs.size(); ++i) { | 100 for (size_t i = 0; i < m_IndirectObjs.size(); ++i) { |
| 104 m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]); | 101 m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]); |
| 105 m_RefObjs.emplace_back(new CPDF_Reference( | 102 m_RefObjs.emplace_back(new CPDF_Reference( |
| 106 m_ObjHolder.get(), m_IndirectObjs[i]->GetObjNum())); | 103 m_ObjHolder.get(), m_IndirectObjs[i]->GetObjNum())); |
| 107 } | 104 } |
| 108 } | 105 } |
| 109 | 106 |
| 110 bool Equal(const CPDF_Object* obj1, const CPDF_Object* obj2) { | 107 bool Equal(CPDF_Object* obj1, CPDF_Object* obj2) { |
| 111 if (obj1 == obj2) | 108 if (obj1 == obj2) |
| 112 return true; | 109 return true; |
| 113 if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType()) | 110 if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType()) |
| 114 return false; | 111 return false; |
| 115 switch (obj1->GetType()) { | 112 switch (obj1->GetType()) { |
| 116 case CPDF_Object::BOOLEAN: | 113 case CPDF_Object::BOOLEAN: |
| 117 return obj1->GetInteger() == obj2->GetInteger(); | 114 return obj1->GetInteger() == obj2->GetInteger(); |
| 118 case CPDF_Object::NUMBER: | 115 case CPDF_Object::NUMBER: |
| 119 return obj1->AsNumber()->IsInteger() == obj2->AsNumber()->IsInteger() && | 116 return obj1->AsNumber()->IsInteger() == obj2->AsNumber()->IsInteger() && |
| 120 obj1->GetInteger() == obj2->GetInteger(); | 117 obj1->GetInteger() == obj2->GetInteger(); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 246 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, |
| 250 nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr}; | 247 nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr}; |
| 251 // Check for direct objects. | 248 // Check for direct objects. |
| 252 for (size_t i = 0; i < m_DirectObjs.size(); ++i) | 249 for (size_t i = 0; i < m_DirectObjs.size(); ++i) |
| 253 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict()); | 250 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict()); |
| 254 | 251 |
| 255 // Check indirect references. | 252 // Check indirect references. |
| 256 const CPDF_Dictionary* const indirect_obj_results[] = { | 253 const CPDF_Dictionary* const indirect_obj_results[] = { |
| 257 nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; | 254 nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj}; |
| 258 for (size_t i = 0; i < m_RefObjs.size(); ++i) | 255 for (size_t i = 0; i < m_RefObjs.size(); ++i) |
| 259 EXPECT_TRUE(Equal(indirect_obj_results[i], m_RefObjs[i]->GetDict())); | 256 EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetDict()); |
| 260 } | 257 } |
| 261 | 258 |
| 262 TEST_F(PDFObjectsTest, GetArray) { | 259 TEST_F(PDFObjectsTest, GetArray) { |
| 263 const CPDF_Array* const direct_obj_results[] = { | 260 const CPDF_Array* const direct_obj_results[] = { |
| 264 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | 261 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, |
| 265 nullptr, m_ArrayObj, nullptr, nullptr, nullptr}; | 262 nullptr, m_ArrayObj, nullptr, nullptr, nullptr}; |
| 266 // Check for direct objects. | 263 // Check for direct objects. |
| 267 for (size_t i = 0; i < m_DirectObjs.size(); ++i) | 264 for (size_t i = 0; i < m_DirectObjs.size(); ++i) |
| 268 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->AsArray()); | 265 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->AsArray()); |
| 269 | 266 |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 ASSERT_TRUE(cloned_dict_object->IsDictionary()); | 780 ASSERT_TRUE(cloned_dict_object->IsDictionary()); |
| 784 | 781 |
| 785 ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); | 782 ScopedDict cloned_dict(cloned_dict_object->AsDictionary()); |
| 786 ASSERT_EQ(1U, cloned_dict->GetCount()); | 783 ASSERT_EQ(1U, cloned_dict->GetCount()); |
| 787 CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); | 784 CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); |
| 788 EXPECT_FALSE(cloned_obj); | 785 EXPECT_FALSE(cloned_obj); |
| 789 } | 786 } |
| 790 | 787 |
| 791 TEST(PDFObjectTest, CloneCheckLoop) { | 788 TEST(PDFObjectTest, CloneCheckLoop) { |
| 792 { | 789 { |
| 793 // Create a dictionary/array pair with a reference loop. | 790 // Create an object with a reference loop. |
| 791 ScopedArray arr_obj(new CPDF_Array); |
| 792 // Dictionary object. |
| 794 CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); | 793 CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); |
| 795 ScopedArray arr_obj(new CPDF_Array); | |
| 796 dict_obj->SetFor("arr", arr_obj.get()); | 794 dict_obj->SetFor("arr", arr_obj.get()); |
| 797 arr_obj->InsertAt(0, dict_obj); | 795 arr_obj->InsertAt(0, dict_obj); |
| 798 | 796 |
| 799 // Clone this object to see whether stack overflow will be triggered. | 797 // Clone this object to see whether stack overflow will be triggered. |
| 800 ScopedArray cloned_array(arr_obj->Clone()->AsArray()); | 798 ScopedArray cloned_array(arr_obj->Clone()->AsArray()); |
| 801 // Cloned object should be the same as the original. | 799 // Cloned object should be the same as the original. |
| 802 ASSERT_TRUE(cloned_array); | 800 ASSERT_TRUE(cloned_array); |
| 803 EXPECT_EQ(1u, cloned_array->GetCount()); | 801 EXPECT_EQ(1u, cloned_array->GetCount()); |
| 804 CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); | 802 CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); |
| 805 ASSERT_TRUE(cloned_dict); | 803 ASSERT_TRUE(cloned_dict); |
| 806 ASSERT_TRUE(cloned_dict->IsDictionary()); | 804 ASSERT_TRUE(cloned_dict->IsDictionary()); |
| 807 // Recursively referenced object is not cloned. | 805 // Recursively referenced object is not cloned. |
| 808 EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); | 806 EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); |
| 809 } | 807 } |
| 810 { | 808 { |
| 811 // Create a dictionary/stream pair with a reference loop. | |
| 812 CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); | |
| 813 ScopedStream stream_obj(new CPDF_Stream(nullptr, 0, dict_obj)); | |
| 814 dict_obj->SetFor("stream", stream_obj.get()); | |
| 815 | |
| 816 // Clone this object to see whether stack overflow will be triggered. | |
| 817 ScopedStream cloned_stream(stream_obj->Clone()->AsStream()); | |
| 818 // Cloned object should be the same as the original. | |
| 819 ASSERT_TRUE(cloned_stream); | |
| 820 CPDF_Object* cloned_dict = cloned_stream->GetDict(); | |
| 821 ASSERT_TRUE(cloned_dict); | |
| 822 ASSERT_TRUE(cloned_dict->IsDictionary()); | |
| 823 // Recursively referenced object is not cloned. | |
| 824 EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("stream")); | |
| 825 } | |
| 826 { | |
| 827 CPDF_IndirectObjectHolder objects_holder; | 809 CPDF_IndirectObjectHolder objects_holder; |
| 828 // Create an object with a reference loop. | 810 // Create an object with a reference loop. |
| 829 CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); | 811 CPDF_Dictionary* dict_obj = new CPDF_Dictionary(); |
| 830 CPDF_Array* arr_obj = new CPDF_Array; | 812 CPDF_Array* arr_obj = new CPDF_Array; |
| 831 objects_holder.AddIndirectObject(dict_obj); | 813 objects_holder.AddIndirectObject(dict_obj); |
| 832 EXPECT_EQ(1u, dict_obj->GetObjNum()); | 814 EXPECT_EQ(1u, dict_obj->GetObjNum()); |
| 833 dict_obj->SetFor("arr", arr_obj); | 815 dict_obj->SetFor("arr", arr_obj); |
| 834 arr_obj->InsertAt( | 816 arr_obj->InsertAt( |
| 835 0, new CPDF_Reference(&objects_holder, dict_obj->GetObjNum())); | 817 0, new CPDF_Reference(&objects_holder, dict_obj->GetObjNum())); |
| 836 CPDF_Object* elem0 = arr_obj->GetObjectAt(0); | 818 CPDF_Object* elem0 = arr_obj->GetObjectAt(0); |
| 837 ASSERT_TRUE(elem0); | 819 ASSERT_TRUE(elem0); |
| 838 ASSERT_TRUE(elem0->IsReference()); | 820 ASSERT_TRUE(elem0->IsReference()); |
| 839 EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); | 821 EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum()); |
| 840 EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); | 822 EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect()); |
| 841 | 823 |
| 842 // Clone this object to see whether stack overflow will be triggered. | 824 // Clone this object to see whether stack overflow will be triggered. |
| 843 ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); | 825 ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject())); |
| 844 // Cloned object should be the same as the original. | 826 // Cloned object should be the same as the original. |
| 845 ASSERT_TRUE(cloned_dict); | 827 ASSERT_TRUE(cloned_dict); |
| 846 CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); | 828 CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); |
| 847 ASSERT_TRUE(cloned_arr); | 829 ASSERT_TRUE(cloned_arr); |
| 848 ASSERT_TRUE(cloned_arr->IsArray()); | 830 ASSERT_TRUE(cloned_arr->IsArray()); |
| 849 EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); | 831 EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount()); |
| 850 // Recursively referenced object is not cloned. | 832 // Recursively referenced object is not cloned. |
| 851 EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); | 833 EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); |
| 852 } | 834 } |
| 853 } | 835 } |
| OLD | NEW |