diff options
Diffstat (limited to 'core/fpdfapi')
-rw-r--r-- | core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp | 181 | ||||
-rw-r--r-- | core/fpdfapi/fpdf_parser/include/cpdf_array.h | 8 |
2 files changed, 189 insertions, 0 deletions
diff --git a/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp b/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp new file mode 100644 index 0000000000..58642a610f --- /dev/null +++ b/core/fpdfapi/fpdf_parser/cpdf_array_unittest.cpp @@ -0,0 +1,181 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_number.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_reference.h" + +#include <memory> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>; + +} // namespace + +TEST(cpdf_array, RemoveAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(3, 3); + int expected[] = {1, 2, 3, 7, 8, 9, 10}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + arr->RemoveAt(4, 2); + int expected2[] = {1, 2, 3, 7, 10}; + EXPECT_EQ(FX_ArraySize(expected2), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected2); ++i) + EXPECT_EQ(expected2[i], arr->GetIntegerAt(i)); + } + { + // When the range is out of bound, RemoveAt has no effect. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->AddInteger(elems[i]); + arr->RemoveAt(8, 5); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->RemoveAt(0, 12); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + arr->RemoveAt(11, 1); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + } +} + +TEST(cpdf_array, InsertAt) { + { + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + EXPECT_EQ(FX_ArraySize(elems), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->InsertAt(3, new CPDF_Number(33)); + arr->InsertAt(6, new CPDF_Number(55)); + arr->InsertAt(12, new CPDF_Number(12)); + int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; + EXPECT_EQ(FX_ArraySize(expected), arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); + } + { + // When the position to insert is beyond the upper bound, + // an element is inserted at that position while other unfilled + // positions have nullptr. + int elems[] = {1, 2}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + arr->InsertAt(10, new CPDF_Number(10)); + EXPECT_EQ(11, arr->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + for (size_t i = FX_ArraySize(elems); i < 10; ++i) + EXPECT_EQ(nullptr, arr->GetObjectAt(i)); + EXPECT_EQ(10, arr->GetIntegerAt(10)); + } +} + +TEST(cpdf_array, Clone) { + { + // Basic case. + int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + ScopedArray arr2(arr->Clone()->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + // Clone() always create new objects. + EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i)); + EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i)); + } + } + { + // Clone() with and without dereferencing reference objects. + static const size_t kNumOfRows = 3; + static const size_t kNumOfRowElems = 5; + int elems[kNumOfRows][kNumOfRowElems] = { + {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}}; + ScopedArray arr(new CPDF_Array); + // Indirect references to indirect objects. + std::unique_ptr<CPDF_IndirectObjectHolder> obj_holder( + new CPDF_IndirectObjectHolder(nullptr)); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = new CPDF_Array; + for (size_t j = 0; j < kNumOfRowElems; ++j) { + CPDF_Number* obj = new CPDF_Number(elems[i][j]); + // Starts object number from 1. + int obj_num = i * kNumOfRowElems + j + 1; + obj_holder->InsertIndirectObject(obj_num, obj); + arr_elem->InsertAt(j, new CPDF_Reference(obj_holder.get(), obj_num), + obj_holder.get()); + } + arr->InsertAt(i, arr_elem); + } + ASSERT_EQ(kNumOfRows, arr->GetCount()); + // Not dereferencing reference objects means just creating new references + // instead of new copies of direct objects. + ScopedArray arr1(arr->Clone(FALSE)->AsArray()); + EXPECT_EQ(arr->GetCount(), arr1->GetCount()); + // Dereferencing reference objects creates new copies of direct objects. + ScopedArray arr2(arr->Clone(TRUE)->AsArray()); + EXPECT_EQ(arr->GetCount(), arr2->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); + CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); + CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); + EXPECT_NE(arr_elem, arr1_elem); + EXPECT_NE(arr_elem, arr2_elem); + for (size_t j = 0; j < kNumOfRowElems; ++j) { + auto elem_obj = arr_elem->GetObjectAt(j); + auto elem_obj1 = arr1_elem->GetObjectAt(j); + auto elem_obj2 = arr2_elem->GetObjectAt(j); + // Results from not deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj1); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elem_obj->GetDirect(), elem_obj1->GetDirect()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_NE(elem_obj, elem_obj2); + EXPECT_TRUE(elem_obj2->IsNumber()); + EXPECT_NE(elem_obj->GetDirect(), elem_obj2); + EXPECT_EQ(elem_obj->GetObjNum(), elem_obj2->GetObjNum()); + EXPECT_EQ(elem_obj->GetInteger(), elem_obj2->GetInteger()); + } + } + arr.reset(); + ASSERT_EQ(kNumOfRows, arr1->GetCount()); + for (size_t i = 0; i < kNumOfRows; ++i) { + for (size_t j = 0; j < kNumOfRowElems; ++j) { + // Results from not deferencing reference objects. + auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); + EXPECT_TRUE(elem_obj1->IsReference()); + EXPECT_EQ(elems[i][j], elem_obj1->GetInteger()); + // Results from deferencing reference objects. + EXPECT_EQ(elems[i][j], + arr2->GetObjectAt(i)->AsArray()->GetIntegerAt(j)); + } + } + } +} + +TEST(cpdf_array, Iterator) { + int elems[] = {-23, -11, 3, 455, 2345877, + 0, 7895330, -12564334, 10000, -100000}; + ScopedArray arr(new CPDF_Array); + for (size_t i = 0; i < FX_ArraySize(elems); ++i) + arr->InsertAt(i, new CPDF_Number(elems[i])); + size_t index = 0; + for (const auto& it : *arr) + EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger()); +} diff --git a/core/fpdfapi/fpdf_parser/include/cpdf_array.h b/core/fpdfapi/fpdf_parser/include/cpdf_array.h index ac3bf41b45..dfe03b9d70 100644 --- a/core/fpdfapi/fpdf_parser/include/cpdf_array.h +++ b/core/fpdfapi/fpdf_parser/include/cpdf_array.h @@ -16,6 +16,9 @@ class CPDF_Array : public CPDF_Object { public: + using iterator = std::vector<CPDF_Object*>::iterator; + using const_iterator = std::vector<CPDF_Object*>::const_iterator; + CPDF_Array(); // CPDF_Object. @@ -57,6 +60,11 @@ class CPDF_Array : public CPDF_Object { AddReference(pDoc, obj->GetObjNum()); } + iterator begin() { return m_Objects.begin(); } + iterator end() { return m_Objects.end(); } + const_iterator begin() const { return m_Objects.begin(); } + const_iterator end() const { return m_Objects.end(); } + protected: ~CPDF_Array() override; |