1 // Copyright 2018 The PDFium Authors
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/fpdf_parser_utility.h"
6
7 #include <memory>
8
9 #include "core/fpdfapi/page/cpdf_pagemodule.h"
10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfapi/parser/cpdf_document.h"
12 #include "core/fpdfapi/parser/cpdf_name.h"
13 #include "core/fpdfapi/parser/cpdf_reference.h"
14 #include "core/fpdfapi/parser/cpdf_string.h"
15 #include "core/fpdfapi/parser/cpdf_test_document.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
TEST(ParserUtilityTest,NameDecode)18 TEST(ParserUtilityTest, NameDecode) {
19 EXPECT_EQ("", PDF_NameDecode(""));
20 EXPECT_EQ("A", PDF_NameDecode("A"));
21 EXPECT_EQ("#", PDF_NameDecode("#"));
22 EXPECT_EQ("#4", PDF_NameDecode("#4"));
23 EXPECT_EQ("A", PDF_NameDecode("#41"));
24 EXPECT_EQ("A1", PDF_NameDecode("#411"));
25 }
26
TEST(ParserUtilityTest,NameEncode)27 TEST(ParserUtilityTest, NameEncode) {
28 EXPECT_EQ("", PDF_NameEncode(""));
29 EXPECT_EQ("A", PDF_NameEncode("A"));
30 EXPECT_EQ("#23", PDF_NameEncode("#"));
31 EXPECT_EQ("#20", PDF_NameEncode(" "));
32 EXPECT_EQ("!@#23$#25^&*#28#29#3C#3E#5B#5D", PDF_NameEncode("!@#$%^&*()<>[]"));
33 EXPECT_EQ("#C2", PDF_NameEncode("\xc2"));
34 EXPECT_EQ("f#C2#A5", PDF_NameEncode("f\xc2\xa5"));
35 }
36
TEST(ParserUtilityTest,ValidateDictType)37 TEST(ParserUtilityTest, ValidateDictType) {
38 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
39
40 // No type.
41 EXPECT_FALSE(ValidateDictType(dict.Get(), "foo"));
42 EXPECT_FALSE(ValidateDictType(dict.Get(), "bar"));
43
44 // Add the wrong object type.
45 dict->SetNewFor<CPDF_String>("Type", L"foo");
46 EXPECT_FALSE(ValidateDictType(dict.Get(), "foo"));
47 EXPECT_FALSE(ValidateDictType(dict.Get(), "bar"));
48
49 // Add the correct object type.
50 dict->SetNewFor<CPDF_Name>("Type", "foo");
51 EXPECT_TRUE(ValidateDictType(dict.Get(), "foo"));
52 EXPECT_FALSE(ValidateDictType(dict.Get(), "bar"));
53 }
54
TEST(ParserUtilityTest,ValidateDictAllResourcesOfType)55 TEST(ParserUtilityTest, ValidateDictAllResourcesOfType) {
56 CPDF_PageModule::Create();
57
58 {
59 // Direct dictionary.
60 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
61
62 // Empty dict is ok.
63 EXPECT_TRUE(ValidateDictAllResourcesOfType(dict.Get(), "foo"));
64 EXPECT_TRUE(ValidateDictAllResourcesOfType(dict.Get(), "bar"));
65
66 // nullptr is not.
67 EXPECT_FALSE(ValidateDictAllResourcesOfType(nullptr, "foo"));
68 EXPECT_FALSE(ValidateDictAllResourcesOfType(nullptr, "bar"));
69
70 // Add two correct dictionary entries and one string entry.
71 auto new_dict = dict->SetNewFor<CPDF_Dictionary>("f1");
72 new_dict->SetNewFor<CPDF_Name>("Type", "foo");
73 new_dict = dict->SetNewFor<CPDF_Dictionary>("f2");
74 new_dict->SetNewFor<CPDF_Name>("Type", "foo");
75 dict->SetNewFor<CPDF_String>("f3", L"foo");
76 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "foo"));
77 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "bar"));
78
79 // Change the string entry to a dictionary, but with the wrong /Type.
80 new_dict = dict->SetNewFor<CPDF_Dictionary>("f3");
81 new_dict->SetNewFor<CPDF_Name>("Type", "bar");
82 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "foo"));
83 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "bar"));
84
85 // Change the /Type to match.
86 new_dict->SetNewFor<CPDF_Name>("Type", "foo");
87 EXPECT_TRUE(ValidateDictAllResourcesOfType(dict.Get(), "foo"));
88 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "bar"));
89 }
90
91 {
92 // Indirect dictionary.
93 auto doc = std::make_unique<CPDF_TestDocument>();
94 auto dict = doc->New<CPDF_Dictionary>();
95
96 // Add a correct dictionary entry.
97 auto new_dict = doc->NewIndirect<CPDF_Dictionary>();
98 new_dict->SetNewFor<CPDF_Name>("Type", "foo");
99 dict->SetNewFor<CPDF_Reference>("f1", doc.get(), new_dict->GetObjNum());
100
101 EXPECT_TRUE(ValidateDictAllResourcesOfType(dict.Get(), "foo"));
102 EXPECT_FALSE(ValidateDictAllResourcesOfType(dict.Get(), "bar"));
103 }
104
105 CPDF_PageModule::Destroy();
106 }
107
TEST(ParserUtilityTest,ValidateDictOptionalType)108 TEST(ParserUtilityTest, ValidateDictOptionalType) {
109 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
110
111 // No type is ok.
112 EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "foo"));
113 EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "bar"));
114
115 // Add the wrong object type.
116 dict->SetNewFor<CPDF_String>("Type", L"foo");
117 EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "foo"));
118 EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "bar"));
119
120 // Add the correct object type.
121 dict->SetNewFor<CPDF_Name>("Type", "foo");
122 EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "foo"));
123 EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "bar"));
124 }
125