Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_filespec_unittest.cpp
Go to the documentation of this file.
1// Copyright 2016 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/fpdfdoc/cpdf_filespec.h"
6
7#include <memory>
8#include <utility>
9#include <vector>
10
11#include "build/build_config.h"
12#include "core/fpdfapi/parser/cpdf_dictionary.h"
13#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
14#include "core/fpdfapi/parser/cpdf_name.h"
15#include "core/fpdfapi/parser/cpdf_number.h"
16#include "core/fpdfapi/parser/cpdf_reference.h"
17#include "core/fpdfapi/parser/cpdf_stream.h"
18#include "core/fpdfapi/parser/cpdf_string.h"
19#include "core/fxcrt/data_vector.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "testing/test_support.h"
22
24 static const std::vector<pdfium::NullTermWstrFuncTestData> test_data = {
25 // Empty src string.
26 {L"", L""},
27 // only file name.
28 {L"test.pdf", L"test.pdf"},
29#if BUILDFLAG(IS_WIN)
30 // With drive identifier.
31 {L"r:\\pdfdocs\\spec.pdf", L"/r/pdfdocs/spec.pdf"},
32 // Relative path.
33 {L"My Document\\test.pdf", L"My Document/test.pdf"},
34 // Absolute path without drive identifier.
35 {L"\\pdfdocs\\spec.pdf", L"//pdfdocs/spec.pdf"},
36 // Absolute path with double backslashes.
37 {L"\\\\pdfdocs\\spec.pdf", L"/pdfdocs/spec.pdf"},
38// Network resource name. It is not supported yet.
39// {L"pclib/eng:\\pdfdocs\\spec.pdf", L"/pclib/eng/pdfdocs/spec.pdf"},
40#elif BUILDFLAG(IS_APPLE)
41 // Absolute path with colon separator.
42 {L"Mac HD:PDFDocs:spec.pdf", L"/Mac HD/PDFDocs/spec.pdf"},
43 // Relative path with colon separator.
44 {L"PDFDocs:spec.pdf", L"PDFDocs/spec.pdf"},
45#else
46 // Relative path.
47 {L"./docs/test.pdf", L"./docs/test.pdf"},
48 // Relative path with parent dir.
49 {L"../test_docs/test.pdf", L"../test_docs/test.pdf"},
50 // Absolute path.
51 {L"/usr/local/home/test.pdf", L"/usr/local/home/test.pdf"},
52#endif
53 };
54 for (const auto& data : test_data) {
55 EXPECT_STREQ(data.expected,
56 CPDF_FileSpec::EncodeFileName(data.input).c_str());
57 // DecodeFileName is the reverse procedure of EncodeFileName.
58 EXPECT_STREQ(data.input,
59 CPDF_FileSpec::DecodeFileName(data.expected).c_str());
60 }
61}
62
64 {
65 // String object.
66 static const pdfium::NullTermWstrFuncTestData test_data = {
67#if BUILDFLAG(IS_WIN)
68 L"/C/docs/test.pdf",
69 L"C:\\docs\\test.pdf"
70#elif BUILDFLAG(IS_APPLE)
71 L"/Mac HD/docs/test.pdf",
72 L"Mac HD:docs:test.pdf"
73#else
74 L"/docs/test.pdf",
75 L"/docs/test.pdf"
76#endif
77 };
78 auto str_obj = pdfium::MakeRetain<CPDF_String>(nullptr, test_data.input);
79 CPDF_FileSpec file_spec(str_obj);
80 EXPECT_STREQ(test_data.expected, file_spec.GetFileName().c_str());
81 }
82 {
83 // Dictionary object.
84 static const pdfium::NullTermWstrFuncTestData test_data[] = {
85#if BUILDFLAG(IS_WIN)
86 {L"/C/docs/test.pdf", L"C:\\docs\\test.pdf"},
87 {L"/D/docs/test.pdf", L"D:\\docs\\test.pdf"},
88 {L"/E/docs/test.pdf", L"E:\\docs\\test.pdf"},
89 {L"/F/docs/test.pdf", L"F:\\docs\\test.pdf"},
90 {L"/G/docs/test.pdf", L"G:\\docs\\test.pdf"},
91#elif BUILDFLAG(IS_APPLE)
92 {L"/Mac HD/docs1/test.pdf", L"Mac HD:docs1:test.pdf"},
93 {L"/Mac HD/docs2/test.pdf", L"Mac HD:docs2:test.pdf"},
94 {L"/Mac HD/docs3/test.pdf", L"Mac HD:docs3:test.pdf"},
95 {L"/Mac HD/docs4/test.pdf", L"Mac HD:docs4:test.pdf"},
96 {L"/Mac HD/docs5/test.pdf", L"Mac HD:docs5:test.pdf"},
97#else
98 {L"/docs/a/test.pdf", L"/docs/a/test.pdf"},
99 {L"/docs/b/test.pdf", L"/docs/b/test.pdf"},
100 {L"/docs/c/test.pdf", L"/docs/c/test.pdf"},
101 {L"/docs/d/test.pdf", L"/docs/d/test.pdf"},
102 {L"/docs/e/test.pdf", L"/docs/e/test.pdf"},
103#endif
104 };
105 // Keyword fields in reverse order of precedence to retrieve the file name.
106 const char* const keywords[] = {"Unix", "Mac", "DOS", "F", "UF"};
107 static_assert(std::size(test_data) == std::size(keywords), "size mismatch");
108 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
109 CPDF_FileSpec file_spec(dict_obj);
110 EXPECT_TRUE(file_spec.GetFileName().IsEmpty());
111 for (size_t i = 0; i < std::size(keywords); ++i) {
112 dict_obj->SetNewFor<CPDF_String>(keywords[i], test_data[i].input);
113 EXPECT_STREQ(test_data[i].expected, file_spec.GetFileName().c_str());
114 }
115
116 // With all the former fields and 'FS' field suggests 'URL' type.
117 dict_obj->SetNewFor<CPDF_String>("FS", "URL", false);
118 // Url string is not decoded.
119 EXPECT_STREQ(test_data[4].input, file_spec.GetFileName().c_str());
120 }
121 {
122 // Invalid object.
123 auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf");
124 CPDF_FileSpec file_spec(name_obj);
125 EXPECT_TRUE(file_spec.GetFileName().IsEmpty());
126 }
127 {
128 // Invalid CPDF_Name objects in dictionary. See https://crbug.com/959183
129 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
130 CPDF_FileSpec file_spec(dict_obj);
131 for (const char* key : {"Unix", "Mac", "DOS", "F", "UF"}) {
132 dict_obj->SetNewFor<CPDF_Name>(key, "http://evil.org");
133 EXPECT_TRUE(file_spec.GetFileName().IsEmpty());
134 }
135 dict_obj->SetNewFor<CPDF_String>("FS", "URL", false);
136 EXPECT_TRUE(file_spec.GetFileName().IsEmpty());
137 }
138}
139
141 {
142 // Invalid object.
143 auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf");
144 CPDF_FileSpec file_spec(name_obj);
145 EXPECT_FALSE(file_spec.GetFileStream());
146 }
147 {
148 // Dictionary object missing its embedded files dictionary.
149 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
150 CPDF_FileSpec file_spec(dict_obj);
151 EXPECT_FALSE(file_spec.GetFileStream());
152 }
153 {
154 // Dictionary object with an empty embedded files dictionary.
155 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
156 dict_obj->SetNewFor<CPDF_Dictionary>("EF");
157 CPDF_FileSpec file_spec(dict_obj);
158 EXPECT_FALSE(file_spec.GetFileStream());
159 }
160 {
161 CPDF_IndirectObjectHolder object_holder;
162 // Dictionary object with a non-empty embedded files dictionary.
163 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
164 dict_obj->SetNewFor<CPDF_Dictionary>("EF");
165 CPDF_FileSpec file_spec(dict_obj);
166
167 const wchar_t file_name[] = L"test.pdf";
168 const char* const keys[] = {"Unix", "Mac", "DOS", "F", "UF"};
169 const char* const streams[] = {"test1", "test2", "test3", "test4", "test5"};
170 static_assert(std::size(keys) == std::size(streams), "size mismatch");
171 RetainPtr<CPDF_Dictionary> file_dict = dict_obj->GetMutableDictFor("EF");
172
173 // Keys in reverse order of precedence to retrieve the file content stream.
174 for (size_t i = 0; i < std::size(keys); ++i) {
175 // Set the file name.
176 dict_obj->SetNewFor<CPDF_String>(keys[i], file_name);
177
178 // Set the file stream.
179 size_t buf_len = strlen(streams[i]) + 1;
180 auto stream_object = object_holder.NewIndirect<CPDF_Stream>(
181 DataVector<uint8_t>(streams[i], streams[i] + buf_len),
182 pdfium::MakeRetain<CPDF_Dictionary>());
183 ASSERT_TRUE(stream_object);
184 const uint32_t stream_object_number = stream_object->GetObjNum();
185 ASSERT_GT(stream_object_number, 0u);
186 file_dict->SetNewFor<CPDF_Reference>(keys[i], &object_holder,
187 stream_object_number);
188
189 // Check that the file content stream is as expected.
190 EXPECT_STREQ(
191 streams[i],
192 file_spec.GetFileStream()->GetUnicodeText().ToUTF8().c_str());
193
194 if (i == 2) {
195 dict_obj->SetNewFor<CPDF_String>("FS", "URL", false);
196 EXPECT_FALSE(file_spec.GetFileStream());
197 }
198 }
199 }
200}
201
203 {
204 // Invalid object.
205 auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf");
206 CPDF_FileSpec file_spec(name_obj);
207 EXPECT_FALSE(file_spec.GetParamsDict());
208 }
209 {
210 CPDF_IndirectObjectHolder object_holder;
211
212 // Dictionary object.
213 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>();
214 dict_obj->SetNewFor<CPDF_Dictionary>("EF");
215 dict_obj->SetNewFor<CPDF_String>("UF", L"test.pdf");
216 CPDF_FileSpec file_spec(dict_obj);
217 EXPECT_FALSE(file_spec.GetParamsDict());
218
219 // Add a file stream to the embedded files dictionary.
220 RetainPtr<CPDF_Dictionary> file_dict = dict_obj->GetMutableDictFor("EF");
221 static constexpr char kHello[] = "hello";
222 auto stream_object = object_holder.NewIndirect<CPDF_Stream>(
223 DataVector<uint8_t>(std::begin(kHello), std::end(kHello)),
224 pdfium::MakeRetain<CPDF_Dictionary>());
225 ASSERT_TRUE(stream_object);
226 const uint32_t stream_object_number = stream_object->GetObjNum();
227 ASSERT_GT(stream_object_number, 0u);
228 file_dict->SetNewFor<CPDF_Reference>("UF", &object_holder,
229 stream_object_number);
230
231 // Add a params dictionary to the file stream.
232 RetainPtr<CPDF_Stream> stream = file_dict->GetMutableStreamFor("UF");
233 RetainPtr<CPDF_Dictionary> stream_dict = stream->GetMutableDict();
234 stream_dict->SetNewFor<CPDF_Dictionary>("Params");
235 EXPECT_TRUE(file_spec.GetParamsDict());
236
237 // Add a parameter to the params dictionary.
238 RetainPtr<CPDF_Dictionary> params_dict =
239 stream_dict->GetMutableDictFor("Params");
240 params_dict->SetNewFor<CPDF_Number>("Size", 6);
241 EXPECT_EQ(6, file_spec.GetParamsDict()->GetIntegerFor("Size"));
242 }
243}
RetainPtr< const CPDF_Dictionary > GetParamsDict() const
WideString GetFileName() const
RetainPtr< const CPDF_Stream > GetFileStream() const
bool IsEmpty() const
Definition widestring.h:118
const wchar_t * c_str() const
Definition widestring.h:81
TEST(FXCRYPT, MD5GenerateEmtpyData)