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