blob: ec982ab58a07b1554430f82474af294661bfca25 [file] [log] [blame]
Lei Zhang94293682016-01-27 18:27:56 -08001// 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
Dan Sinclairaa403d32016-03-15 14:57:22 -04005#include "core/fpdfapi/fpdf_parser/cpdf_boolean.h"
6#include "core/fpdfapi/fpdf_parser/cpdf_null.h"
7#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
8#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h"
9#include "core/fpdfapi/fpdf_parser/include/cpdf_name.h"
10#include "core/fpdfapi/fpdf_parser/include/cpdf_number.h"
11#include "core/fpdfapi/fpdf_parser/include/cpdf_reference.h"
12#include "core/fpdfapi/fpdf_parser/include/cpdf_stream.h"
13#include "core/fpdfapi/fpdf_parser/include/cpdf_string.h"
Lei Zhang94293682016-01-27 18:27:56 -080014
15#include <memory>
Dan Sinclair3ebd1212016-03-09 09:59:23 -050016#include <string>
Lei Zhang94293682016-01-27 18:27:56 -080017#include <vector>
18
Dan Sinclairaa403d32016-03-15 14:57:22 -040019#include "core/fpdfapi/fpdf_parser/include/cpdf_indirect_object_holder.h"
Dan Sinclaira8a28e02016-03-23 15:41:39 -040020#include "core/fxcrt/include/fx_basic.h"
Lei Zhang94293682016-01-27 18:27:56 -080021#include "testing/gtest/include/gtest/gtest.h"
22
Wei Libb53a5d2016-02-03 10:04:19 -080023namespace {
24
25using ScopedArray = std::unique_ptr<CPDF_Array, ReleaseDeleter<CPDF_Array>>;
weilia470b5e2016-08-23 22:08:37 -070026using ScopedDict =
27 std::unique_ptr<CPDF_Dictionary, ReleaseDeleter<CPDF_Dictionary>>;
Wei Libb53a5d2016-02-03 10:04:19 -080028
29void TestArrayAccessors(const CPDF_Array* arr,
30 size_t index,
31 const char* str_val,
32 const char* const_str_val,
33 int int_val,
34 float float_val,
35 CPDF_Array* arr_val,
36 CPDF_Dictionary* dict_val,
37 CPDF_Stream* stream_val) {
38 EXPECT_STREQ(str_val, arr->GetStringAt(index).c_str());
Wei Libb53a5d2016-02-03 10:04:19 -080039 EXPECT_EQ(int_val, arr->GetIntegerAt(index));
40 EXPECT_EQ(float_val, arr->GetNumberAt(index));
41 EXPECT_EQ(float_val, arr->GetFloatAt(index));
42 EXPECT_EQ(arr_val, arr->GetArrayAt(index));
43 EXPECT_EQ(dict_val, arr->GetDictAt(index));
44 EXPECT_EQ(stream_val, arr->GetStreamAt(index));
45}
46
47} // namespace
48
Lei Zhang94293682016-01-27 18:27:56 -080049class PDFObjectsTest : public testing::Test {
50 public:
51 void SetUp() override {
52 // Initialize different kinds of objects.
53 // Boolean objects.
54 CPDF_Boolean* boolean_false_obj = new CPDF_Boolean(false);
55 CPDF_Boolean* boolean_true_obj = new CPDF_Boolean(true);
56 // Number objects.
57 CPDF_Number* number_int_obj = new CPDF_Number(1245);
58 CPDF_Number* number_float_obj = new CPDF_Number(9.00345f);
59 // String objects.
60 CPDF_String* str_reg_obj = new CPDF_String(L"A simple test");
61 CPDF_String* str_spec_obj = new CPDF_String(L"\t\n");
62 // Name object.
63 CPDF_Name* name_obj = new CPDF_Name("space");
64 // Array object.
Wei Li8f952272016-01-29 18:04:42 -080065 m_ArrayObj = new CPDF_Array;
66 m_ArrayObj->InsertAt(0, new CPDF_Number(8902));
67 m_ArrayObj->InsertAt(1, new CPDF_Name("address"));
Lei Zhang94293682016-01-27 18:27:56 -080068 // Dictionary object.
69 m_DictObj = new CPDF_Dictionary;
70 m_DictObj->SetAt("bool", new CPDF_Boolean(false));
71 m_DictObj->SetAt("num", new CPDF_Number(0.23f));
72 // Stream object.
73 const char content[] = "abcdefghijklmnopqrstuvwxyz";
74 size_t buf_len = FX_ArraySize(content);
75 uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_len));
76 memcpy(buf, content, buf_len);
77 m_StreamDictObj = new CPDF_Dictionary;
78 m_StreamDictObj->SetAt("key1", new CPDF_String(L" test dict"));
79 m_StreamDictObj->SetAt("key2", new CPDF_Number(-1));
80 CPDF_Stream* stream_obj = new CPDF_Stream(buf, buf_len, m_StreamDictObj);
81 // Null Object.
82 CPDF_Null* null_obj = new CPDF_Null;
83 // All direct objects.
84 CPDF_Object* objs[] = {boolean_false_obj, boolean_true_obj, number_int_obj,
85 number_float_obj, str_reg_obj, str_spec_obj,
Wei Li8f952272016-01-29 18:04:42 -080086 name_obj, m_ArrayObj, m_DictObj,
Lei Zhang94293682016-01-27 18:27:56 -080087 stream_obj, null_obj};
Wei Li8f952272016-01-29 18:04:42 -080088 m_DirectObjTypes = {
89 CPDF_Object::BOOLEAN, CPDF_Object::BOOLEAN, CPDF_Object::NUMBER,
90 CPDF_Object::NUMBER, CPDF_Object::STRING, CPDF_Object::STRING,
91 CPDF_Object::NAME, CPDF_Object::ARRAY, CPDF_Object::DICTIONARY,
92 CPDF_Object::STREAM, CPDF_Object::NULLOBJ};
93 for (size_t i = 0; i < FX_ArraySize(objs); ++i)
Lei Zhang94293682016-01-27 18:27:56 -080094 m_DirectObjs.emplace_back(objs[i]);
95
96 // Indirect references to indirect objects.
dsinclaira61c01e2016-08-24 10:31:23 -070097 m_ObjHolder.reset(new CPDF_IndirectObjectHolder());
Wei Li8f952272016-01-29 18:04:42 -080098 m_IndirectObjs = {boolean_true_obj, number_int_obj, str_spec_obj, name_obj,
99 m_ArrayObj, m_DictObj, stream_obj};
100 for (size_t i = 0; i < m_IndirectObjs.size(); ++i) {
101 m_ObjHolder->AddIndirectObject(m_IndirectObjs[i]);
102 m_RefObjs.emplace_back(new CPDF_Reference(
103 m_ObjHolder.get(), m_IndirectObjs[i]->GetObjNum()));
Lei Zhang94293682016-01-27 18:27:56 -0800104 }
105 }
106
Wei Li8f952272016-01-29 18:04:42 -0800107 bool Equal(CPDF_Object* obj1, CPDF_Object* obj2) {
108 if (obj1 == obj2)
109 return true;
110 if (!obj1 || !obj2 || obj1->GetType() != obj2->GetType())
111 return false;
112 switch (obj1->GetType()) {
113 case CPDF_Object::BOOLEAN:
114 return obj1->GetInteger() == obj2->GetInteger();
115 case CPDF_Object::NUMBER:
116 return obj1->AsNumber()->IsInteger() == obj2->AsNumber()->IsInteger() &&
117 obj1->GetInteger() == obj2->GetInteger();
118 case CPDF_Object::STRING:
119 case CPDF_Object::NAME:
120 return obj1->GetString() == obj2->GetString();
121 case CPDF_Object::ARRAY: {
122 const CPDF_Array* array1 = obj1->AsArray();
123 const CPDF_Array* array2 = obj2->AsArray();
124 if (array1->GetCount() != array2->GetCount())
125 return false;
126 for (size_t i = 0; i < array1->GetCount(); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700127 if (!Equal(array1->GetObjectAt(i), array2->GetObjectAt(i)))
Wei Li8f952272016-01-29 18:04:42 -0800128 return false;
129 }
130 return true;
131 }
132 case CPDF_Object::DICTIONARY: {
133 const CPDF_Dictionary* dict1 = obj1->AsDictionary();
134 const CPDF_Dictionary* dict2 = obj2->AsDictionary();
135 if (dict1->GetCount() != dict2->GetCount())
136 return false;
137 for (CPDF_Dictionary::const_iterator it = dict1->begin();
138 it != dict1->end(); ++it) {
tsepez7b1ccf92016-04-14 11:04:57 -0700139 if (!Equal(it->second, dict2->GetObjectBy(it->first)))
Wei Li8f952272016-01-29 18:04:42 -0800140 return false;
141 }
142 return true;
143 }
144 case CPDF_Object::NULLOBJ:
145 return true;
146 case CPDF_Object::STREAM: {
147 const CPDF_Stream* stream1 = obj1->AsStream();
148 const CPDF_Stream* stream2 = obj2->AsStream();
149 if (!stream1->GetDict() && !stream2->GetDict())
150 return true;
151 // Compare dictionaries.
152 if (!Equal(stream1->GetDict(), stream2->GetDict()))
153 return false;
154 // Compare sizes.
155 if (stream1->GetRawSize() != stream2->GetRawSize())
156 return false;
157 // Compare contents.
158 // Since this function is used for testing Clone(), only memory based
159 // streams need to be handled.
160 if (!stream1->IsMemoryBased() || !stream2->IsMemoryBased())
161 return false;
162 return FXSYS_memcmp(stream1->GetRawData(), stream2->GetRawData(),
163 stream1->GetRawSize()) == 0;
164 }
165 case CPDF_Object::REFERENCE:
166 return obj1->AsReference()->GetRefObjNum() ==
167 obj2->AsReference()->GetRefObjNum();
168 }
169 return false;
170 }
171
Lei Zhang94293682016-01-27 18:27:56 -0800172 protected:
173 using ScopedObj = std::unique_ptr<CPDF_Object, ReleaseDeleter<CPDF_Object>>;
174
175 // m_ObjHolder needs to be declared first and destructed last since it also
176 // refers to some objects in m_DirectObjs.
177 std::unique_ptr<CPDF_IndirectObjectHolder> m_ObjHolder;
178 std::vector<ScopedObj> m_DirectObjs;
Wei Li8f952272016-01-29 18:04:42 -0800179 std::vector<int> m_DirectObjTypes;
Lei Zhang94293682016-01-27 18:27:56 -0800180 std::vector<ScopedObj> m_RefObjs;
181 CPDF_Dictionary* m_DictObj;
182 CPDF_Dictionary* m_StreamDictObj;
Wei Li8f952272016-01-29 18:04:42 -0800183 CPDF_Array* m_ArrayObj;
184 std::vector<CPDF_Object*> m_IndirectObjs;
Lei Zhang94293682016-01-27 18:27:56 -0800185};
186
187TEST_F(PDFObjectsTest, GetString) {
thestigb8bf55f2016-05-21 21:08:05 -0700188 const char* const direct_obj_results[] = {
Lei Zhang94293682016-01-27 18:27:56 -0800189 "false", "true", "1245", "9.00345", "A simple test", "\t\n", "space",
190 "", "", "", ""};
191 // Check for direct objects.
Wei Li8f952272016-01-29 18:04:42 -0800192 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800193 EXPECT_STREQ(direct_obj_results[i], m_DirectObjs[i]->GetString().c_str());
Lei Zhang94293682016-01-27 18:27:56 -0800194
195 // Check indirect references.
thestigb8bf55f2016-05-21 21:08:05 -0700196 const char* const indirect_obj_results[] = {"true", "1245", "\t\n", "space",
197 "", "", ""};
Wei Li8f952272016-01-29 18:04:42 -0800198 for (size_t i = 0; i < m_RefObjs.size(); ++i) {
Wei Libb53a5d2016-02-03 10:04:19 -0800199 EXPECT_STREQ(indirect_obj_results[i], m_RefObjs[i]->GetString().c_str());
Lei Zhang94293682016-01-27 18:27:56 -0800200 }
201}
202
Wei Li8f952272016-01-29 18:04:42 -0800203TEST_F(PDFObjectsTest, GetUnicodeText) {
thestigb8bf55f2016-05-21 21:08:05 -0700204 const wchar_t* const direct_obj_results[] = {
Wei Li8f952272016-01-29 18:04:42 -0800205 L"", L"", L"", L"", L"A simple test",
206 L"\t\n", L"space", L"", L"", L"abcdefghijklmnopqrstuvwxyz",
207 L""};
208 // Check for direct objects.
dsinclair685bb882016-04-20 07:32:39 -0700209 for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
Wei Libb53a5d2016-02-03 10:04:19 -0800210 EXPECT_STREQ(direct_obj_results[i],
211 m_DirectObjs[i]->GetUnicodeText().c_str());
dsinclair685bb882016-04-20 07:32:39 -0700212 }
Wei Li8f952272016-01-29 18:04:42 -0800213
214 // Check indirect references.
215 for (const auto& it : m_RefObjs)
Wei Libb53a5d2016-02-03 10:04:19 -0800216 EXPECT_STREQ(L"", it->GetUnicodeText().c_str());
Wei Li8f952272016-01-29 18:04:42 -0800217}
218
Lei Zhang94293682016-01-27 18:27:56 -0800219TEST_F(PDFObjectsTest, GetNumber) {
220 const FX_FLOAT direct_obj_results[] = {0, 0, 1245, 9.00345f, 0, 0,
221 0, 0, 0, 0, 0};
222 // Check for direct objects.
Wei Li8f952272016-01-29 18:04:42 -0800223 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800224 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetNumber());
Lei Zhang94293682016-01-27 18:27:56 -0800225
226 // Check indirect references.
227 const FX_FLOAT indirect_obj_results[] = {0, 1245, 0, 0, 0, 0, 0};
Wei Li8f952272016-01-29 18:04:42 -0800228 for (size_t i = 0; i < m_RefObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800229 EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetNumber());
Lei Zhang94293682016-01-27 18:27:56 -0800230}
231
232TEST_F(PDFObjectsTest, GetInteger) {
233 const int direct_obj_results[] = {0, 1, 1245, 9, 0, 0, 0, 0, 0, 0, 0};
234 // Check for direct objects.
Wei Li8f952272016-01-29 18:04:42 -0800235 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800236 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetInteger());
Lei Zhang94293682016-01-27 18:27:56 -0800237
238 // Check indirect references.
239 const int indirect_obj_results[] = {1, 1245, 0, 0, 0, 0, 0};
Wei Li8f952272016-01-29 18:04:42 -0800240 for (size_t i = 0; i < m_RefObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800241 EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetInteger());
Lei Zhang94293682016-01-27 18:27:56 -0800242}
243
244TEST_F(PDFObjectsTest, GetDict) {
thestigb8bf55f2016-05-21 21:08:05 -0700245 const CPDF_Dictionary* const direct_obj_results[] = {
Lei Zhang94293682016-01-27 18:27:56 -0800246 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
247 nullptr, nullptr, m_DictObj, m_StreamDictObj, nullptr};
248 // Check for direct objects.
Wei Li8f952272016-01-29 18:04:42 -0800249 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800250 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->GetDict());
Lei Zhang94293682016-01-27 18:27:56 -0800251
252 // Check indirect references.
thestigb8bf55f2016-05-21 21:08:05 -0700253 const CPDF_Dictionary* const indirect_obj_results[] = {
Lei Zhang94293682016-01-27 18:27:56 -0800254 nullptr, nullptr, nullptr, nullptr, nullptr, m_DictObj, m_StreamDictObj};
Wei Li8f952272016-01-29 18:04:42 -0800255 for (size_t i = 0; i < m_RefObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800256 EXPECT_EQ(indirect_obj_results[i], m_RefObjs[i]->GetDict());
Lei Zhang94293682016-01-27 18:27:56 -0800257}
Wei Li8f952272016-01-29 18:04:42 -0800258
259TEST_F(PDFObjectsTest, GetArray) {
thestigb8bf55f2016-05-21 21:08:05 -0700260 const CPDF_Array* const direct_obj_results[] = {
Wei Li8f952272016-01-29 18:04:42 -0800261 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
262 nullptr, m_ArrayObj, nullptr, nullptr, nullptr};
263 // Check for direct objects.
264 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
thestigb8bf55f2016-05-21 21:08:05 -0700265 EXPECT_EQ(direct_obj_results[i], m_DirectObjs[i]->AsArray());
Wei Li8f952272016-01-29 18:04:42 -0800266
267 // Check indirect references.
268 for (const auto& it : m_RefObjs)
thestigb8bf55f2016-05-21 21:08:05 -0700269 EXPECT_EQ(nullptr, it->AsArray());
Wei Li8f952272016-01-29 18:04:42 -0800270}
271
272TEST_F(PDFObjectsTest, Clone) {
273 // Check for direct objects.
274 for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
275 ScopedObj obj(m_DirectObjs[i]->Clone());
276 EXPECT_TRUE(Equal(m_DirectObjs[i].get(), obj.get()));
277 }
278
279 // Check indirect references.
280 for (const auto& it : m_RefObjs) {
281 ScopedObj obj(it->Clone());
282 EXPECT_TRUE(Equal(it.get(), obj.get()));
283 }
284}
285
286TEST_F(PDFObjectsTest, GetType) {
287 // Check for direct objects.
288 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800289 EXPECT_EQ(m_DirectObjTypes[i], m_DirectObjs[i]->GetType());
Wei Li8f952272016-01-29 18:04:42 -0800290
291 // Check indirect references.
292 for (const auto& it : m_RefObjs)
Wei Libb53a5d2016-02-03 10:04:19 -0800293 EXPECT_EQ(CPDF_Object::REFERENCE, it->GetType());
Wei Li8f952272016-01-29 18:04:42 -0800294}
295
296TEST_F(PDFObjectsTest, GetDirect) {
297 // Check for direct objects.
298 for (size_t i = 0; i < m_DirectObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800299 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->GetDirect());
Wei Li8f952272016-01-29 18:04:42 -0800300
301 // Check indirect references.
302 for (size_t i = 0; i < m_RefObjs.size(); ++i)
Wei Libb53a5d2016-02-03 10:04:19 -0800303 EXPECT_EQ(m_IndirectObjs[i], m_RefObjs[i]->GetDirect());
Wei Li8f952272016-01-29 18:04:42 -0800304}
305
306TEST_F(PDFObjectsTest, SetString) {
307 // Check for direct objects.
308 const char* const set_values[] = {"true", "fake", "3.125f", "097",
309 "changed", "", "NewName"};
thestigb8bf55f2016-05-21 21:08:05 -0700310 const char* const expected[] = {"true", "false", "3.125", "97",
311 "changed", "", "NewName"};
Wei Li8f952272016-01-29 18:04:42 -0800312 for (size_t i = 0; i < FX_ArraySize(set_values); ++i) {
313 m_DirectObjs[i]->SetString(set_values[i]);
Wei Libb53a5d2016-02-03 10:04:19 -0800314 EXPECT_STREQ(expected[i], m_DirectObjs[i]->GetString().c_str());
Wei Li8f952272016-01-29 18:04:42 -0800315 }
316}
317
318TEST_F(PDFObjectsTest, IsTypeAndAsType) {
319 // Check for direct objects.
320 for (size_t i = 0; i < m_DirectObjs.size(); ++i) {
321 if (m_DirectObjTypes[i] == CPDF_Object::ARRAY) {
322 EXPECT_TRUE(m_DirectObjs[i]->IsArray());
Wei Libb53a5d2016-02-03 10:04:19 -0800323 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsArray());
Wei Li8f952272016-01-29 18:04:42 -0800324 } else {
325 EXPECT_FALSE(m_DirectObjs[i]->IsArray());
Wei Libb53a5d2016-02-03 10:04:19 -0800326 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsArray());
Wei Li8f952272016-01-29 18:04:42 -0800327 }
328
329 if (m_DirectObjTypes[i] == CPDF_Object::BOOLEAN) {
330 EXPECT_TRUE(m_DirectObjs[i]->IsBoolean());
Wei Libb53a5d2016-02-03 10:04:19 -0800331 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsBoolean());
Wei Li8f952272016-01-29 18:04:42 -0800332 } else {
333 EXPECT_FALSE(m_DirectObjs[i]->IsBoolean());
Wei Libb53a5d2016-02-03 10:04:19 -0800334 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsBoolean());
Wei Li8f952272016-01-29 18:04:42 -0800335 }
336
337 if (m_DirectObjTypes[i] == CPDF_Object::NAME) {
338 EXPECT_TRUE(m_DirectObjs[i]->IsName());
Wei Libb53a5d2016-02-03 10:04:19 -0800339 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsName());
Wei Li8f952272016-01-29 18:04:42 -0800340 } else {
341 EXPECT_FALSE(m_DirectObjs[i]->IsName());
Wei Libb53a5d2016-02-03 10:04:19 -0800342 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsName());
Wei Li8f952272016-01-29 18:04:42 -0800343 }
344
345 if (m_DirectObjTypes[i] == CPDF_Object::NUMBER) {
346 EXPECT_TRUE(m_DirectObjs[i]->IsNumber());
Wei Libb53a5d2016-02-03 10:04:19 -0800347 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsNumber());
Wei Li8f952272016-01-29 18:04:42 -0800348 } else {
349 EXPECT_FALSE(m_DirectObjs[i]->IsNumber());
Wei Libb53a5d2016-02-03 10:04:19 -0800350 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsNumber());
Wei Li8f952272016-01-29 18:04:42 -0800351 }
352
353 if (m_DirectObjTypes[i] == CPDF_Object::STRING) {
354 EXPECT_TRUE(m_DirectObjs[i]->IsString());
Wei Libb53a5d2016-02-03 10:04:19 -0800355 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsString());
Wei Li8f952272016-01-29 18:04:42 -0800356 } else {
357 EXPECT_FALSE(m_DirectObjs[i]->IsString());
Wei Libb53a5d2016-02-03 10:04:19 -0800358 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsString());
Wei Li8f952272016-01-29 18:04:42 -0800359 }
360
361 if (m_DirectObjTypes[i] == CPDF_Object::DICTIONARY) {
362 EXPECT_TRUE(m_DirectObjs[i]->IsDictionary());
Wei Libb53a5d2016-02-03 10:04:19 -0800363 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsDictionary());
Wei Li8f952272016-01-29 18:04:42 -0800364 } else {
365 EXPECT_FALSE(m_DirectObjs[i]->IsDictionary());
Wei Libb53a5d2016-02-03 10:04:19 -0800366 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsDictionary());
Wei Li8f952272016-01-29 18:04:42 -0800367 }
368
369 if (m_DirectObjTypes[i] == CPDF_Object::STREAM) {
370 EXPECT_TRUE(m_DirectObjs[i]->IsStream());
Wei Libb53a5d2016-02-03 10:04:19 -0800371 EXPECT_EQ(m_DirectObjs[i].get(), m_DirectObjs[i]->AsStream());
Wei Li8f952272016-01-29 18:04:42 -0800372 } else {
373 EXPECT_FALSE(m_DirectObjs[i]->IsStream());
Wei Libb53a5d2016-02-03 10:04:19 -0800374 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsStream());
Wei Li8f952272016-01-29 18:04:42 -0800375 }
376
377 EXPECT_FALSE(m_DirectObjs[i]->IsReference());
Wei Libb53a5d2016-02-03 10:04:19 -0800378 EXPECT_EQ(nullptr, m_DirectObjs[i]->AsReference());
Wei Li8f952272016-01-29 18:04:42 -0800379 }
380 // Check indirect references.
381 for (size_t i = 0; i < m_RefObjs.size(); ++i) {
382 EXPECT_TRUE(m_RefObjs[i]->IsReference());
Wei Libb53a5d2016-02-03 10:04:19 -0800383 EXPECT_EQ(m_RefObjs[i].get(), m_RefObjs[i]->AsReference());
384 }
385}
386
387TEST(PDFArrayTest, GetMatrix) {
388 float elems[][6] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
389 {1, 2, 3, 4, 5, 6},
390 {2.3f, 4.05f, 3, -2, -3, 0.0f},
391 {0.05f, 0.1f, 0.56f, 0.67f, 1.34f, 99.9f}};
392 for (size_t i = 0; i < FX_ArraySize(elems); ++i) {
393 ScopedArray arr(new CPDF_Array);
394 CFX_Matrix matrix(elems[i][0], elems[i][1], elems[i][2], elems[i][3],
395 elems[i][4], elems[i][5]);
396 for (size_t j = 0; j < 6; ++j)
397 arr->AddNumber(elems[i][j]);
398 CFX_Matrix arr_matrix = arr->GetMatrix();
399 EXPECT_EQ(matrix.GetA(), arr_matrix.GetA());
400 EXPECT_EQ(matrix.GetB(), arr_matrix.GetB());
401 EXPECT_EQ(matrix.GetC(), arr_matrix.GetC());
402 EXPECT_EQ(matrix.GetD(), arr_matrix.GetD());
403 EXPECT_EQ(matrix.GetE(), arr_matrix.GetE());
404 EXPECT_EQ(matrix.GetF(), arr_matrix.GetF());
405 }
406}
407
408TEST(PDFArrayTest, GetRect) {
409 float elems[][4] = {{0.0f, 0.0f, 0.0f, 0.0f},
410 {1, 2, 5, 6},
411 {2.3f, 4.05f, -3, 0.0f},
412 {0.05f, 0.1f, 1.34f, 99.9f}};
413 for (size_t i = 0; i < FX_ArraySize(elems); ++i) {
414 ScopedArray arr(new CPDF_Array);
415 CFX_FloatRect rect(elems[i]);
416 for (size_t j = 0; j < 4; ++j)
417 arr->AddNumber(elems[i][j]);
418 CFX_FloatRect arr_rect = arr->GetRect();
419 EXPECT_EQ(rect.left, arr_rect.left);
420 EXPECT_EQ(rect.right, arr_rect.right);
421 EXPECT_EQ(rect.bottom, arr_rect.bottom);
422 EXPECT_EQ(rect.top, arr_rect.top);
423 }
424}
425
426TEST(PDFArrayTest, GetTypeAt) {
427 {
428 // Boolean array.
thestigb8bf55f2016-05-21 21:08:05 -0700429 const bool vals[] = {true, false, false, true, true};
Wei Libb53a5d2016-02-03 10:04:19 -0800430 ScopedArray arr(new CPDF_Array);
431 for (size_t i = 0; i < FX_ArraySize(vals); ++i)
432 arr->InsertAt(i, new CPDF_Boolean(vals[i]));
433 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
434 TestArrayAccessors(arr.get(), i, // Array and index.
435 vals[i] ? "true" : "false", // String value.
436 nullptr, // Const string value.
437 vals[i] ? 1 : 0, // Integer value.
438 0, // Float value.
439 nullptr, // Array value.
440 nullptr, // Dictionary value.
441 nullptr); // Stream value.
442 }
443 }
444 {
445 // Integer array.
thestigb8bf55f2016-05-21 21:08:05 -0700446 const int vals[] = {10, 0, -345, 2089345456, -1000000000, 567, 93658767};
Wei Libb53a5d2016-02-03 10:04:19 -0800447 ScopedArray arr(new CPDF_Array);
448 for (size_t i = 0; i < FX_ArraySize(vals); ++i)
449 arr->InsertAt(i, new CPDF_Number(vals[i]));
450 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
451 char buf[33];
452 TestArrayAccessors(arr.get(), i, // Array and index.
453 FXSYS_itoa(vals[i], buf, 10), // String value.
454 nullptr, // Const string value.
455 vals[i], // Integer value.
456 vals[i], // Float value.
457 nullptr, // Array value.
458 nullptr, // Dictionary value.
459 nullptr); // Stream value.
460 }
461 }
462 {
463 // Float array.
thestigb8bf55f2016-05-21 21:08:05 -0700464 const float vals[] = {0.0f, 0, 10, 10.0f, 0.0345f,
465 897.34f, -2.5f, -1.0f, -345.0f, -0.0f};
466 const char* const expected_str[] = {
467 "0", "0", "10", "10", "0.0345", "897.34", "-2.5", "-1", "-345", "0"};
Wei Libb53a5d2016-02-03 10:04:19 -0800468 ScopedArray arr(new CPDF_Array);
469 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
470 arr->InsertAt(i, new CPDF_Number(vals[i]));
471 }
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 ScopedArray string_array(new CPDF_Array);
488 ScopedArray name_array(new CPDF_Array);
489 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
490 string_array->InsertAt(i, new CPDF_String(vals[i], false));
491 name_array->InsertAt(i, new CPDF_Name(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 ScopedArray arr(new CPDF_Array);
515 for (size_t i = 0; i < 3; ++i)
516 arr->InsertAt(i, new CPDF_Null);
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 ScopedArray arr(new CPDF_Array);
532 for (size_t i = 0; i < 3; ++i) {
533 vals[i] = new CPDF_Array;
534 for (size_t j = 0; j < 3; ++j) {
535 int value = j + 100;
536 vals[i]->InsertAt(i, new CPDF_Number(value));
537 }
538 arr->InsertAt(i, vals[i]);
539 }
540 for (size_t i = 0; i < 3; ++i) {
541 TestArrayAccessors(arr.get(), i, // Array and index.
542 "", // String value.
543 nullptr, // Const string value.
544 0, // Integer value.
545 0, // Float value.
546 vals[i], // Array value.
547 nullptr, // Dictionary value.
548 nullptr); // Stream value.
549 }
550 }
551 {
552 // Dictionary array.
553 CPDF_Dictionary* vals[3];
554 ScopedArray arr(new CPDF_Array);
555 for (size_t i = 0; i < 3; ++i) {
556 vals[i] = new CPDF_Dictionary;
557 for (size_t j = 0; j < 3; ++j) {
558 std::string key("key");
559 char buf[33];
560 key.append(FXSYS_itoa(j, buf, 10));
561 int value = j + 200;
tsepez7b1ccf92016-04-14 11:04:57 -0700562 vals[i]->SetAt(key.c_str(), new CPDF_Number(value));
Wei Libb53a5d2016-02-03 10:04:19 -0800563 }
564 arr->InsertAt(i, vals[i]);
565 }
566 for (size_t i = 0; i < 3; ++i) {
567 TestArrayAccessors(arr.get(), i, // Array and index.
568 "", // String value.
569 nullptr, // Const string value.
570 0, // Integer value.
571 0, // Float value.
572 nullptr, // Array value.
573 vals[i], // Dictionary value.
574 nullptr); // Stream value.
575 }
576 }
577 {
578 // Stream array.
579 CPDF_Dictionary* vals[3];
580 CPDF_Stream* stream_vals[3];
581 ScopedArray arr(new CPDF_Array);
582 for (size_t i = 0; i < 3; ++i) {
583 vals[i] = new CPDF_Dictionary;
584 for (size_t j = 0; j < 3; ++j) {
585 std::string key("key");
586 char buf[33];
587 key.append(FXSYS_itoa(j, buf, 10));
588 int value = j + 200;
tsepez7b1ccf92016-04-14 11:04:57 -0700589 vals[i]->SetAt(key.c_str(), new CPDF_Number(value));
Wei Libb53a5d2016-02-03 10:04:19 -0800590 }
591 uint8_t content[] = "content: this is a stream";
592 size_t data_size = FX_ArraySize(content);
593 uint8_t* data = reinterpret_cast<uint8_t*>(malloc(data_size));
594 memcpy(data, content, data_size);
595 stream_vals[i] = new CPDF_Stream(data, data_size, vals[i]);
596 arr->InsertAt(i, stream_vals[i]);
597 }
598 for (size_t i = 0; i < 3; ++i) {
599 TestArrayAccessors(arr.get(), i, // Array and index.
600 "", // String value.
601 nullptr, // Const string value.
602 0, // Integer value.
603 0, // Float value.
604 nullptr, // Array value.
605 vals[i], // Dictionary value.
606 stream_vals[i]); // Stream value.
607 }
608 }
609 {
610 // Mixed array.
611 ScopedArray arr(new CPDF_Array);
612 // Array arr will take ownership of all the objects inserted.
613 arr->InsertAt(0, new CPDF_Boolean(true));
614 arr->InsertAt(1, new CPDF_Boolean(false));
615 arr->InsertAt(2, new CPDF_Number(0));
616 arr->InsertAt(3, new CPDF_Number(-1234));
617 arr->InsertAt(4, new CPDF_Number(2345.0f));
618 arr->InsertAt(5, new CPDF_Number(0.05f));
619 arr->InsertAt(6, new CPDF_String("", false));
620 arr->InsertAt(7, new CPDF_String("It is a test!", false));
621 arr->InsertAt(8, new CPDF_Name("NAME"));
622 arr->InsertAt(9, new CPDF_Name("test"));
623 arr->InsertAt(10, new CPDF_Null());
624 CPDF_Array* arr_val = new CPDF_Array;
625 arr_val->AddNumber(1);
626 arr_val->AddNumber(2);
627 arr->InsertAt(11, arr_val);
628 CPDF_Dictionary* dict_val = new CPDF_Dictionary;
629 dict_val->SetAt("key1", new CPDF_String("Linda", false));
630 dict_val->SetAt("key2", new CPDF_String("Zoe", false));
631 arr->InsertAt(12, dict_val);
632 CPDF_Dictionary* stream_dict = new CPDF_Dictionary;
633 stream_dict->SetAt("key1", new CPDF_String("John", false));
634 stream_dict->SetAt("key2", new CPDF_String("King", false));
635 uint8_t data[] = "A stream for test";
636 // The data buffer will be owned by stream object, so it needs to be
637 // dynamically allocated.
638 size_t buf_size = sizeof(data);
639 uint8_t* buf = reinterpret_cast<uint8_t*>(malloc(buf_size));
640 memcpy(buf, data, buf_size);
641 CPDF_Stream* stream_val = new CPDF_Stream(buf, buf_size, stream_dict);
642 arr->InsertAt(13, stream_val);
643 const char* const expected_str[] = {
644 "true", "false", "0", "-1234", "2345", "0.05", "",
645 "It is a test!", "NAME", "test", "", "", "", ""};
Wei Libb53a5d2016-02-03 10:04:19 -0800646 const int expected_int[] = {1, 0, 0, -1234, 2345, 0, 0,
647 0, 0, 0, 0, 0, 0, 0};
648 const float expected_float[] = {0, 0, 0, -1234, 2345, 0.05f, 0,
649 0, 0, 0, 0, 0, 0, 0};
650 for (size_t i = 0; i < arr->GetCount(); ++i) {
651 EXPECT_STREQ(expected_str[i], arr->GetStringAt(i).c_str());
Wei Libb53a5d2016-02-03 10:04:19 -0800652 EXPECT_EQ(expected_int[i], arr->GetIntegerAt(i));
653 EXPECT_EQ(expected_float[i], arr->GetNumberAt(i));
654 EXPECT_EQ(expected_float[i], arr->GetFloatAt(i));
655 if (i == 11)
656 EXPECT_EQ(arr_val, arr->GetArrayAt(i));
657 else
658 EXPECT_EQ(nullptr, arr->GetArrayAt(i));
659 if (i == 13) {
660 EXPECT_EQ(stream_dict, arr->GetDictAt(i));
661 EXPECT_EQ(stream_val, arr->GetStreamAt(i));
662 } else {
663 EXPECT_EQ(nullptr, arr->GetStreamAt(i));
664 if (i == 12)
665 EXPECT_EQ(dict_val, arr->GetDictAt(i));
666 else
667 EXPECT_EQ(nullptr, arr->GetDictAt(i));
668 }
669 }
670 }
671}
672
673TEST(PDFArrayTest, AddNumber) {
674 float vals[] = {1.0f, -1.0f, 0, 0.456734f,
675 12345.54321f, 0.5f, 1000, 0.000045f};
676 ScopedArray arr(new CPDF_Array);
677 for (size_t i = 0; i < FX_ArraySize(vals); ++i)
678 arr->AddNumber(vals[i]);
679 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700680 EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType());
681 EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber());
Wei Libb53a5d2016-02-03 10:04:19 -0800682 }
683}
684
685TEST(PDFArrayTest, AddInteger) {
686 int vals[] = {0, 1, 934435456, 876, 10000, -1, -24354656, -100};
687 ScopedArray arr(new CPDF_Array);
688 for (size_t i = 0; i < FX_ArraySize(vals); ++i)
689 arr->AddInteger(vals[i]);
690 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700691 EXPECT_EQ(CPDF_Object::NUMBER, arr->GetObjectAt(i)->GetType());
692 EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber());
Wei Libb53a5d2016-02-03 10:04:19 -0800693 }
694}
695
696TEST(PDFArrayTest, AddStringAndName) {
697 const char* vals[] = {"", "a", "ehjhRIOYTTFdfcdnv", "122323",
698 "$#%^&**", " ", "This is a test.\r\n"};
699 ScopedArray string_array(new CPDF_Array);
700 ScopedArray name_array(new CPDF_Array);
701 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
702 string_array->AddString(vals[i]);
703 name_array->AddName(vals[i]);
704 }
705 for (size_t i = 0; i < FX_ArraySize(vals); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700706 EXPECT_EQ(CPDF_Object::STRING, string_array->GetObjectAt(i)->GetType());
707 EXPECT_STREQ(vals[i], string_array->GetObjectAt(i)->GetString().c_str());
708 EXPECT_EQ(CPDF_Object::NAME, name_array->GetObjectAt(i)->GetType());
709 EXPECT_STREQ(vals[i], name_array->GetObjectAt(i)->GetString().c_str());
Wei Libb53a5d2016-02-03 10:04:19 -0800710 }
711}
712
tsepezbd567552016-03-29 14:51:50 -0700713TEST(PDFArrayTest, AddReferenceAndGetObjectAt) {
Wei Libb53a5d2016-02-03 10:04:19 -0800714 std::unique_ptr<CPDF_IndirectObjectHolder> holder(
dsinclaira61c01e2016-08-24 10:31:23 -0700715 new CPDF_IndirectObjectHolder());
Wei Libb53a5d2016-02-03 10:04:19 -0800716 CPDF_Boolean* boolean_obj = new CPDF_Boolean(true);
717 CPDF_Number* int_obj = new CPDF_Number(-1234);
718 CPDF_Number* float_obj = new CPDF_Number(2345.089f);
719 CPDF_String* str_obj = new CPDF_String("Adsfdsf 343434 %&&*\n", false);
720 CPDF_Name* name_obj = new CPDF_Name("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 ScopedArray arr(new CPDF_Array);
726 ScopedArray 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 // All the indirect objects inserted will be owned by holder.
dsinclair03bd7c72016-08-23 20:13:41 -0700730 holder->ReplaceIndirectObjectIfHigherGeneration(obj_nums[i],
731 indirect_objs[i]);
Wei Libb53a5d2016-02-03 10:04:19 -0800732 arr->AddReference(holder.get(), obj_nums[i]);
733 arr1->AddReference(holder.get(), indirect_objs[i]);
734 }
735 // Check indirect objects.
736 for (size_t i = 0; i < FX_ArraySize(obj_nums); ++i)
dsinclair03bd7c72016-08-23 20:13:41 -0700737 EXPECT_EQ(indirect_objs[i], holder->GetOrParseIndirectObject(obj_nums[i]));
Wei Libb53a5d2016-02-03 10:04:19 -0800738 // Check arrays.
739 EXPECT_EQ(arr->GetCount(), arr1->GetCount());
740 for (size_t i = 0; i < arr->GetCount(); ++i) {
tsepezbd567552016-03-29 14:51:50 -0700741 EXPECT_EQ(CPDF_Object::REFERENCE, arr->GetObjectAt(i)->GetType());
742 EXPECT_EQ(indirect_objs[i], arr->GetObjectAt(i)->GetDirect());
743 EXPECT_EQ(indirect_objs[i], arr->GetDirectObjectAt(i));
744 EXPECT_EQ(CPDF_Object::REFERENCE, arr1->GetObjectAt(i)->GetType());
745 EXPECT_EQ(indirect_objs[i], arr1->GetObjectAt(i)->GetDirect());
746 EXPECT_EQ(indirect_objs[i], arr1->GetDirectObjectAt(i));
Wei Li8f952272016-01-29 18:04:42 -0800747 }
748}
weilia470b5e2016-08-23 22:08:37 -0700749
thestig22b176d2016-08-25 11:14:21 -0700750TEST(PDFArrayTest, CloneDirectObject) {
751 CPDF_IndirectObjectHolder objects_holder;
752 ScopedArray array(new CPDF_Array);
753 array->AddReference(&objects_holder, 1234);
754 ASSERT_EQ(1U, array->GetCount());
755 CPDF_Object* obj = array->GetObjectAt(0);
756 ASSERT_TRUE(obj);
757 EXPECT_TRUE(obj->IsReference());
758
759 CPDF_Object* cloned_array_object = array->CloneDirectObject();
760 ASSERT_TRUE(cloned_array_object);
761 ASSERT_TRUE(cloned_array_object->IsArray());
762
763 ScopedArray cloned_array(cloned_array_object->AsArray());
764 ASSERT_EQ(1U, cloned_array->GetCount());
765 CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0);
766 EXPECT_FALSE(cloned_obj);
767}
768
769TEST(PDFDictionaryTest, CloneDirectObject) {
770 CPDF_IndirectObjectHolder objects_holder;
771 ScopedDict dict(new CPDF_Dictionary);
772 dict->SetAtReference("foo", &objects_holder, 1234);
773 ASSERT_EQ(1U, dict->GetCount());
774 CPDF_Object* obj = dict->GetObjectBy("foo");
775 ASSERT_TRUE(obj);
776 EXPECT_TRUE(obj->IsReference());
777
778 CPDF_Object* cloned_dict_object = dict->CloneDirectObject();
779 ASSERT_TRUE(cloned_dict_object);
780 ASSERT_TRUE(cloned_dict_object->IsDictionary());
781
782 ScopedDict cloned_dict(cloned_dict_object->AsDictionary());
783 ASSERT_EQ(1U, cloned_dict->GetCount());
784 CPDF_Object* cloned_obj = cloned_dict->GetObjectBy("foo");
785 EXPECT_FALSE(cloned_obj);
786}
787
weilia470b5e2016-08-23 22:08:37 -0700788TEST(PDFObjectTest, CloneCheckLoop) {
789 {
790 // Create an object with a reference loop.
791 ScopedArray arr_obj(new CPDF_Array);
792 // Dictionary object.
793 CPDF_Dictionary* dict_obj = new CPDF_Dictionary;
794 dict_obj->SetAt("arr", arr_obj.get());
795 arr_obj->InsertAt(0, dict_obj);
796
797 // Clone this object to see whether stack overflow will be triggered.
798 ScopedArray cloned_array(arr_obj->Clone()->AsArray());
799 // Cloned object should be the same as the original.
800 ASSERT_TRUE(cloned_array);
801 EXPECT_EQ(1u, cloned_array->GetCount());
802 CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0);
803 ASSERT_TRUE(cloned_dict);
804 ASSERT_TRUE(cloned_dict->IsDictionary());
805 // Recursively referenced object is not cloned.
806 EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectBy("arr"));
807 }
808 {
thestig22b176d2016-08-25 11:14:21 -0700809 CPDF_IndirectObjectHolder objects_holder;
weilia470b5e2016-08-23 22:08:37 -0700810 // Create an object with a reference loop.
811 CPDF_Dictionary* dict_obj = new CPDF_Dictionary;
812 CPDF_Array* arr_obj = new CPDF_Array;
thestig22b176d2016-08-25 11:14:21 -0700813 objects_holder.AddIndirectObject(dict_obj);
weilia470b5e2016-08-23 22:08:37 -0700814 EXPECT_EQ(1u, dict_obj->GetObjNum());
815 dict_obj->SetAt("arr", arr_obj);
thestig22b176d2016-08-25 11:14:21 -0700816 arr_obj->InsertAt(0, dict_obj, &objects_holder);
weilia470b5e2016-08-23 22:08:37 -0700817 CPDF_Object* elem0 = arr_obj->GetObjectAt(0);
818 ASSERT_TRUE(elem0);
819 ASSERT_TRUE(elem0->IsReference());
820 EXPECT_EQ(1u, elem0->AsReference()->GetRefObjNum());
821 EXPECT_EQ(dict_obj, elem0->AsReference()->GetDirect());
822
823 // Clone this object to see whether stack overflow will be triggered.
824 ScopedDict cloned_dict(ToDictionary(dict_obj->CloneDirectObject()));
825 // Cloned object should be the same as the original.
826 ASSERT_TRUE(cloned_dict);
827 CPDF_Object* cloned_arr = cloned_dict->GetObjectBy("arr");
828 ASSERT_TRUE(cloned_arr);
829 ASSERT_TRUE(cloned_arr->IsArray());
830 EXPECT_EQ(1u, cloned_arr->AsArray()->GetCount());
831 // Recursively referenced object is not cloned.
832 EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0));
833 }
834}