blob: 74b3d7b469ecd84315504ab581df402d4b0cefc8 [file] [log] [blame]
Jane Liu53aafa92017-07-12 19:55:02 -04001// Copyright 2017 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
Jane Liuf63e8132017-07-25 18:11:27 -04005#include <memory>
6#include <string>
7#include <vector>
8
Jane Liu53aafa92017-07-12 19:55:02 -04009#include "public/fpdf_attachment.h"
Jane Liu18ae06d2017-07-18 10:15:16 -040010#include "public/fpdfview.h"
Jane Liu53aafa92017-07-12 19:55:02 -040011#include "testing/embedder_test.h"
12
13class FPDFAttachmentEmbeddertest : public EmbedderTest {};
14
15TEST_F(FPDFAttachmentEmbeddertest, ExtractAttachments) {
16 // Open a file with two attachments.
17 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
18 EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
19
Jane Liu18ae06d2017-07-18 10:15:16 -040020 // Retrieve the first attachment.
21 FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
22 ASSERT_TRUE(attachment);
23
Jane Liu53aafa92017-07-12 19:55:02 -040024 // Check that the name of the first attachment is correct.
Jane Liu18ae06d2017-07-18 10:15:16 -040025 unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
Jane Liu53aafa92017-07-12 19:55:02 -040026 std::vector<char> buf(len);
Jane Liu18ae06d2017-07-18 10:15:16 -040027 EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
Jane Liu53aafa92017-07-12 19:55:02 -040028 EXPECT_STREQ(L"1.txt",
29 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
30 .c_str());
Jane Liu18ae06d2017-07-18 10:15:16 -040031
32 // Check that the content of the first attachment is correct.
33 len = FPDFAttachment_GetFile(attachment, nullptr, 0);
34 buf.clear();
35 buf.resize(len);
36 ASSERT_EQ(4u, FPDFAttachment_GetFile(attachment, buf.data(), len));
37 EXPECT_EQ(std::string("test"), std::string(buf.data(), 4));
38
39 // Check that a non-existent key does not exist.
40 EXPECT_FALSE(
41 FPDFAttachment_HasKey(attachment, GetFPDFWideString(L"none").get()));
42
43 // Check that the string value of a non-string dictionary entry is empty.
44 std::unique_ptr<unsigned short, pdfium::FreeDeleter> size_key =
45 GetFPDFWideString(L"Size");
46 EXPECT_EQ(FPDF_OBJECT_NUMBER,
47 FPDFAttachment_GetValueType(attachment, size_key.get()));
48 EXPECT_EQ(2u, FPDFAttachment_GetStringValue(attachment, size_key.get(),
49 nullptr, 0));
50
51 // Check that the creation date of the first attachment is correct.
52 std::unique_ptr<unsigned short, pdfium::FreeDeleter> date_key =
53 GetFPDFWideString(L"CreationDate");
54 len = FPDFAttachment_GetStringValue(attachment, date_key.get(), nullptr, 0);
55 buf.clear();
56 buf.resize(len);
57 EXPECT_EQ(48u, FPDFAttachment_GetStringValue(attachment, date_key.get(),
58 buf.data(), len));
59 EXPECT_STREQ(L"D:20170712214438-07'00'",
60 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
61 .c_str());
62
63 // Retrieve the second attachment.
64 attachment = FPDFDoc_GetAttachment(document(), 1);
65 ASSERT_TRUE(attachment);
66
67 // Retrieve the second attachment file.
68 len = FPDFAttachment_GetFile(attachment, nullptr, 0);
69 buf.clear();
70 buf.resize(len);
71 EXPECT_EQ(5869u, FPDFAttachment_GetFile(attachment, buf.data(), len));
72
73 // Check that the calculated checksum of the file data matches expectation.
74 const char kCheckSum[] = "72afcddedf554dda63c0c88e06f1ce18";
75 const wchar_t kCheckSumW[] = L"<72AFCDDEDF554DDA63C0C88E06F1CE18>";
76 const std::string generated_checksum =
77 GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len);
78 EXPECT_EQ(kCheckSum, generated_checksum);
79
80 // Check that the stored checksum matches expectation.
81 std::unique_ptr<unsigned short, pdfium::FreeDeleter> checksum_key =
82 GetFPDFWideString(L"CheckSum");
83 len =
84 FPDFAttachment_GetStringValue(attachment, checksum_key.get(), nullptr, 0);
85 buf.clear();
86 buf.resize(len);
87 EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, checksum_key.get(),
88 buf.data(), len));
89 EXPECT_EQ(kCheckSumW,
90 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
Jane Liu53aafa92017-07-12 19:55:02 -040091}
Jane Liu54a42142017-07-24 16:40:54 -040092
93TEST_F(FPDFAttachmentEmbeddertest, AddAttachments) {
94 // Open a file with two attachments.
95 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
96 EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
97
98 // Check that adding an attachment with an empty name would fail.
99 EXPECT_FALSE(FPDFDoc_AddAttachment(document(), nullptr));
100
101 // Add an attachment to the beginning of the embedded file list.
102 std::unique_ptr<unsigned short, pdfium::FreeDeleter> file_name =
103 GetFPDFWideString(L"0.txt");
104 FPDF_ATTACHMENT attachment =
105 FPDFDoc_AddAttachment(document(), file_name.get());
106
107 // Check that writing to a file with nullptr but non-zero bytes would fail.
108 EXPECT_FALSE(FPDFAttachment_SetFile(attachment, document(), nullptr, 10));
109
110 // Set the new attachment's file.
111 constexpr char kContents1[] = "Hello!";
112 EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents1,
113 strlen(kContents1)));
114
115 // Verify the name of the new attachment (i.e. the first attachment).
116 attachment = FPDFDoc_GetAttachment(document(), 0);
117 ASSERT_TRUE(attachment);
118 unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
119 std::vector<char> buf(len);
120 EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
121 EXPECT_STREQ(L"0.txt",
122 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
123 .c_str());
124
125 // Verify the content of the new attachment (i.e. the first attachment).
126 len = FPDFAttachment_GetFile(attachment, nullptr, 0);
127 buf.clear();
128 buf.resize(len);
129 ASSERT_EQ(6u, FPDFAttachment_GetFile(attachment, buf.data(), len));
130 EXPECT_EQ(std::string(kContents1), std::string(buf.data(), 6));
131
132 // Add an attachment to the end of the embedded file list and set its file.
133 file_name = GetFPDFWideString(L"z.txt");
134 attachment = FPDFDoc_AddAttachment(document(), file_name.get());
135 constexpr char kContents2[] = "World!";
136 EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents2,
137 strlen(kContents2)));
138 EXPECT_EQ(4, FPDFDoc_GetAttachmentCount(document()));
139
140 // Verify the name of the new attachment (i.e. the fourth attachment).
141 attachment = FPDFDoc_GetAttachment(document(), 3);
142 ASSERT_TRUE(attachment);
143 len = FPDFAttachment_GetName(attachment, nullptr, 0);
144 buf.clear();
145 buf.resize(len);
146 EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
147 EXPECT_STREQ(L"z.txt",
148 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
149 .c_str());
150
151 // Verify the content of the new attachment (i.e. the fourth attachment).
152 len = FPDFAttachment_GetFile(attachment, nullptr, 0);
153 buf.clear();
154 buf.resize(len);
155 ASSERT_EQ(6u, FPDFAttachment_GetFile(attachment, buf.data(), len));
156 EXPECT_EQ(std::string(kContents2), std::string(buf.data(), 6));
157}
158
159TEST_F(FPDFAttachmentEmbeddertest, AddAttachmentsWithParams) {
160 // Open a file with two attachments.
161 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
162 EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
163
164 // Add an attachment to the embedded file list.
165 std::unique_ptr<unsigned short, pdfium::FreeDeleter> file_name =
166 GetFPDFWideString(L"5.txt");
167 FPDF_ATTACHMENT attachment =
168 FPDFDoc_AddAttachment(document(), file_name.get());
169 constexpr char kContents[] = "Hello World!";
170 EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), kContents,
171 strlen(kContents)));
172
173 // Set the date to be an arbitrary value.
174 std::unique_ptr<unsigned short, pdfium::FreeDeleter> date_key =
175 GetFPDFWideString(L"CreationDate");
176 constexpr wchar_t kDateW[] = L"D:20170720161527-04'00'";
177 std::unique_ptr<unsigned short, pdfium::FreeDeleter> ws_date =
178 GetFPDFWideString(kDateW);
179 EXPECT_TRUE(
180 FPDFAttachment_SetStringValue(attachment, date_key.get(), ws_date.get()));
181
182 // Set the checksum to be an arbitrary value.
183 std::unique_ptr<unsigned short, pdfium::FreeDeleter> checksum_key =
184 GetFPDFWideString(L"CheckSum");
185 constexpr wchar_t kCheckSumW[] = L"<ABCDEF01234567899876543210FEDCBA>";
186 std::unique_ptr<unsigned short, pdfium::FreeDeleter> ws_checksum =
187 GetFPDFWideString(kCheckSumW);
188 EXPECT_TRUE(FPDFAttachment_SetStringValue(attachment, checksum_key.get(),
189 ws_checksum.get()));
190
191 // Verify the name of the new attachment (i.e. the second attachment).
192 attachment = FPDFDoc_GetAttachment(document(), 1);
193 ASSERT_TRUE(attachment);
194 unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
195 std::vector<char> buf(len);
196 EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
197 EXPECT_STREQ(L"5.txt",
198 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
199 .c_str());
200
201 // Verify the content of the new attachment.
202 len = FPDFAttachment_GetFile(attachment, nullptr, 0);
203 buf.clear();
204 buf.resize(len);
205 ASSERT_EQ(12u, FPDFAttachment_GetFile(attachment, buf.data(), len));
206 EXPECT_EQ(std::string(kContents), std::string(buf.data(), 12));
207
208 // Verify the creation date of the new attachment.
209 len = FPDFAttachment_GetStringValue(attachment, date_key.get(), nullptr, 0);
210 buf.clear();
211 buf.resize(len);
212 EXPECT_EQ(48u, FPDFAttachment_GetStringValue(attachment, date_key.get(),
213 buf.data(), len));
214 EXPECT_STREQ(kDateW,
215 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
216 .c_str());
217
218 // Verify the checksum of the new attachment.
219 len =
220 FPDFAttachment_GetStringValue(attachment, checksum_key.get(), nullptr, 0);
221 buf.clear();
222 buf.resize(len);
223 EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, checksum_key.get(),
224 buf.data(), len));
225 EXPECT_STREQ(kCheckSumW,
226 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
227 .c_str());
228
229 // Overwrite the existing file with empty content, and check that the checksum
230 // gets updated to the correct value.
231 EXPECT_TRUE(FPDFAttachment_SetFile(attachment, document(), nullptr, 0));
232 EXPECT_EQ(0u, FPDFAttachment_GetFile(attachment, nullptr, 0));
233 len =
234 FPDFAttachment_GetStringValue(attachment, checksum_key.get(), nullptr, 0);
235 buf.clear();
236 buf.resize(len);
237 EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, checksum_key.get(),
238 buf.data(), len));
239 EXPECT_EQ(L"<D41D8CD98F00B204E9800998ECF8427E>",
240 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
Jane Liuf63e8132017-07-25 18:11:27 -0400241}
242
243TEST_F(FPDFAttachmentEmbeddertest, DeleteAttachment) {
244 // Open a file with two attachments.
245 ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
246 EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
247
248 // Verify the name of the first attachment.
249 FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
250 unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
251 std::vector<char> buf(len);
252 EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
253 EXPECT_STREQ(L"1.txt",
254 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
255 .c_str());
256
257 // Delete the first attachment.
258 EXPECT_TRUE(FPDFDoc_DeleteAttachment(document(), 0));
259 EXPECT_EQ(1, FPDFDoc_GetAttachmentCount(document()));
260
261 // Verify the name of the new first attachment.
262 attachment = FPDFDoc_GetAttachment(document(), 0);
263 len = FPDFAttachment_GetName(attachment, nullptr, 0);
264 buf.clear();
265 buf.resize(len);
266 EXPECT_EQ(26u, FPDFAttachment_GetName(attachment, buf.data(), len));
267 EXPECT_STREQ(L"attached.pdf",
268 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
269 .c_str());
270}