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