Added FPDFDoc_DeleteAttachment()

Added an API for deleting an attachment and an embedder test for it.

Bug=pdfium:174

Change-Id: I97a1367a197bceb96ecef55c36b1599beccd95a6
Reviewed-on: https://pdfium-review.googlesource.com/8932
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/fpdfsdk/fpdfattachment.cpp b/fpdfsdk/fpdfattachment.cpp
index 78fccf4..0cb623f 100644
--- a/fpdfsdk/fpdfattachment.cpp
+++ b/fpdfsdk/fpdfattachment.cpp
@@ -112,6 +112,19 @@
   return nameTree.LookupValueAndName(index, &csName);
 }
 
+DLLEXPORT FPDF_BOOL STDCALL FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document,
+                                                     int index) {
+  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+  if (!pDoc || index < 0)
+    return false;
+
+  CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
+  if (static_cast<size_t>(index) >= nameTree.GetCount())
+    return false;
+
+  return nameTree.DeleteValueAndName(index);
+}
+
 DLLEXPORT unsigned long STDCALL
 FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,
                        void* buffer,
diff --git a/fpdfsdk/fpdfattachment_embeddertest.cpp b/fpdfsdk/fpdfattachment_embeddertest.cpp
index f4d0bfc..74b3d7b 100644
--- a/fpdfsdk/fpdfattachment_embeddertest.cpp
+++ b/fpdfsdk/fpdfattachment_embeddertest.cpp
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "public/fpdf_attachment.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
@@ -234,4 +238,33 @@
                                                buf.data(), len));
   EXPECT_EQ(L"<D41D8CD98F00B204E9800998ECF8427E>",
             GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
-}
\ No newline at end of file
+}
+
+TEST_F(FPDFAttachmentEmbeddertest, DeleteAttachment) {
+  // Open a file with two attachments.
+  ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
+  EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+
+  // Verify the name of the first attachment.
+  FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
+  unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  std::vector<char> buf(len);
+  EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"1.txt",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+
+  // Delete the first attachment.
+  EXPECT_TRUE(FPDFDoc_DeleteAttachment(document(), 0));
+  EXPECT_EQ(1, FPDFDoc_GetAttachmentCount(document()));
+
+  // Verify the name of the new first attachment.
+  attachment = FPDFDoc_GetAttachment(document(), 0);
+  len = FPDFAttachment_GetName(attachment, nullptr, 0);
+  buf.clear();
+  buf.resize(len);
+  EXPECT_EQ(26u, FPDFAttachment_GetName(attachment, buf.data(), len));
+  EXPECT_STREQ(L"attached.pdf",
+               GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+                   .c_str());
+}
diff --git a/public/fpdf_attachment.h b/public/fpdf_attachment.h
index e604d59..a5a8465 100644
--- a/public/fpdf_attachment.h
+++ b/public/fpdf_attachment.h
@@ -45,6 +45,19 @@
                                                         int index);
 
 // Experimental API.
+// Delete the embedded attachment at |index| in |document|. Note that this does
+// not remove the attachment data from the PDF file; it simply removes the
+// file's entry in the embedded files name tree so that it does not appear in
+// the attachment list. This behavior may change in the future.
+//
+//   document - handle to a document.
+//   index    - the index of the embedded file to be deleted.
+//
+// Returns true if successful.
+DLLEXPORT FPDF_BOOL STDCALL FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document,
+                                                     int index);
+
+// Experimental API.
 // Get the name of the |attachment| file. |buffer| is only modified if |buflen|
 // is longer than the length of the file name. On errors, |buffer| is unmodified
 // and the returned length is 0.