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