Home | History | Annotate | Download | only in fpdfsdk
      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 
     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 
     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 
    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 
    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