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