summaryrefslogtreecommitdiff
path: root/fpdfsdk/fpdfattachment.cpp
diff options
context:
space:
mode:
authorJane Liu <janeliulwq@google.com>2017-07-24 16:40:54 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-07-24 21:19:22 +0000
commit54a4214c86bc790cc2a3ae454b1aa709e868fa1a (patch)
treeebd92341381e3a16d386caf5280bc7626925b910 /fpdfsdk/fpdfattachment.cpp
parent6a388c1595522e26a633fbed1022752f4c80ac0c (diff)
downloadpdfium-54a4214c86bc790cc2a3ae454b1aa709e868fa1a.tar.xz
Basic APIs and tests for adding attachments
1. Added APIs for adding attachments, setting attachment files, and modifying attachment dictionary entries. * Added two embedder tests covering all new APIs. Bug=pdfium:174 Change-Id: I65f43cd6ca4887b71f9f7bcee64a87ba6b7e2706 Reviewed-on: https://pdfium-review.googlesource.com/8671 Commit-Queue: Jane Liu <janeliulwq@google.com> Reviewed-by: Lei Zhang <thestig@chromium.org> Reviewed-by: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'fpdfsdk/fpdfattachment.cpp')
-rw-r--r--fpdfsdk/fpdfattachment.cpp146
1 files changed, 145 insertions, 1 deletions
diff --git a/fpdfsdk/fpdfattachment.cpp b/fpdfsdk/fpdfattachment.cpp
index 7d8cce736b..724664b05d 100644
--- a/fpdfsdk/fpdfattachment.cpp
+++ b/fpdfsdk/fpdfattachment.cpp
@@ -4,14 +4,45 @@
#include "public/fpdf_attachment.h"
+#include "core/fdrm/crypto/fx_crypt.h"
#include "core/fpdfapi/page/cpdf_streamparser.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
#include "core/fpdfdoc/cpdf_filespec.h"
#include "core/fpdfdoc/cpdf_nametree.h"
+#include "core/fxcrt/cfx_datetime.h"
+#include "core/fxcrt/fx_extension.h"
#include "fpdfsdk/fsdk_define.h"
+namespace {
+
+CFX_ByteString CFXByteStringHexDecode(const CFX_ByteString& bsHex) {
+ uint8_t* result = nullptr;
+ uint32_t size = 0;
+ HexDecode(bsHex.raw_str(), bsHex.GetLength(), &result, &size);
+ CFX_ByteString bsDecoded(result, size);
+ FX_Free(result);
+ return bsDecoded;
+}
+
+CFX_ByteString GenerateMD5Base16(const void* contents,
+ const unsigned long len) {
+ uint8_t digest[16];
+ CRYPT_MD5Generate(reinterpret_cast<const uint8_t*>(contents), len, digest);
+ char buf[32];
+ for (int i = 0; i < 16; ++i)
+ FXSYS_IntToTwoHexChars(digest[i], &buf[i * 2]);
+
+ return CFX_ByteString(buf, 32);
+}
+
+} // namespace
+
DLLEXPORT int STDCALL FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document) {
CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
if (!pDoc)
@@ -20,6 +51,50 @@ DLLEXPORT int STDCALL FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document) {
return CPDF_NameTree(pDoc, "EmbeddedFiles").GetCount();
}
+DLLEXPORT FPDF_ATTACHMENT FPDFDoc_AddAttachment(FPDF_DOCUMENT document,
+ FPDF_WIDESTRING name) {
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ CFX_WideString wsName =
+ CFX_WideString::FromUTF16LE(name, CFX_WideString::WStringLength(name));
+ if (!pDoc || wsName.IsEmpty())
+ return nullptr;
+
+ CPDF_Dictionary* pRoot = pDoc->GetRoot();
+ if (!pRoot)
+ return nullptr;
+
+ // Retrieve the document's Names dictionary; create it if missing.
+ CPDF_Dictionary* pNames = pRoot->GetDictFor("Names");
+ if (!pNames) {
+ pNames = pDoc->NewIndirect<CPDF_Dictionary>();
+ pRoot->SetNewFor<CPDF_Reference>("Names", pDoc, pNames->GetObjNum());
+ }
+
+ // Create the EmbeddedFiles dictionary if missing.
+ if (!pNames->GetDictFor("EmbeddedFiles")) {
+ CPDF_Dictionary* pFiles = pDoc->NewIndirect<CPDF_Dictionary>();
+ pFiles->SetNewFor<CPDF_Array>("Names");
+ pNames->SetNewFor<CPDF_Reference>("EmbeddedFiles", pDoc,
+ pFiles->GetObjNum());
+ }
+
+ // Set up the basic entries in the filespec dictionary.
+ CPDF_Dictionary* pFile = pDoc->NewIndirect<CPDF_Dictionary>();
+ pFile->SetNewFor<CPDF_Name>("Type", "Filespec");
+ pFile->SetNewFor<CPDF_String>("UF", wsName);
+ pFile->SetNewFor<CPDF_String>("F", wsName);
+
+ // Add the new attachment name and filespec into the document's EmbeddedFiles.
+ CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
+ if (!nameTree.AddValueAndName(
+ pdfium::MakeUnique<CPDF_Reference>(pDoc, pFile->GetObjNum()),
+ wsName)) {
+ return nullptr;
+ }
+
+ return pFile;
+}
+
DLLEXPORT FPDF_ATTACHMENT STDCALL FPDFDoc_GetAttachment(FPDF_DOCUMENT document,
int index) {
CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
@@ -73,6 +148,28 @@ FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_WIDESTRING key) {
return pObj->GetType();
}
+DLLEXPORT FPDF_BOOL STDCALL
+FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,
+ FPDF_WIDESTRING key,
+ FPDF_WIDESTRING value) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+ if (!pFile)
+ return false;
+
+ CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+ if (!pParamsDict)
+ return false;
+
+ CFX_ByteString bsKey = CFXByteStringFromFPDFWideString(key);
+ CFX_ByteString bsValue = CFXByteStringFromFPDFWideString(value);
+ bool bEncodedAsHex = bsKey == "CheckSum";
+ if (bEncodedAsHex)
+ bsValue = CFXByteStringHexDecode(bsValue);
+
+ pParamsDict->SetNewFor<CPDF_String>(bsKey, bsValue, bEncodedAsHex);
+ return true;
+}
+
DLLEXPORT unsigned long STDCALL
FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
FPDF_WIDESTRING key,
@@ -88,7 +185,7 @@ FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
CFX_ByteString bsKey = CFXByteStringFromFPDFWideString(key);
CFX_WideString value = pParamsDict->GetUnicodeTextFor(bsKey);
- if (bsKey == "CheckSum") {
+ if (bsKey == "CheckSum" && !value.IsEmpty()) {
CPDF_String* stringValue = pParamsDict->GetObjectFor(bsKey)->AsString();
if (stringValue->IsHex()) {
value =
@@ -101,6 +198,53 @@ FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
return Utf16EncodeMaybeCopyAndReturnLength(value, buffer, buflen);
}
+DLLEXPORT FPDF_BOOL FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,
+ FPDF_DOCUMENT document,
+ const void* contents,
+ const unsigned long len) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ if (!pFile || !pFile->IsDictionary() || !pDoc || len > INT_MAX)
+ return false;
+
+ // An empty content must have a zero length.
+ if (!contents && len != 0)
+ return false;
+
+ // Create a dictionary for the new embedded file stream.
+ auto pFileStreamDict = pdfium::MakeUnique<CPDF_Dictionary>();
+ CPDF_Dictionary* pParamsDict =
+ pFileStreamDict->SetNewFor<CPDF_Dictionary>("Params");
+
+ // Set the size of the new file in the dictionary.
+ pFileStreamDict->SetNewFor<CPDF_Number>("DL", static_cast<int>(len));
+ pParamsDict->SetNewFor<CPDF_Number>("Size", static_cast<int>(len));
+
+ // Set the creation date of the new attachment in the dictionary.
+ CFX_DateTime dateTime;
+ dateTime.Now();
+ CFX_ByteString bsDateTime;
+ bsDateTime.Format("D:%d%02d%02d%02d%02d%02d", dateTime.GetYear(),
+ dateTime.GetMonth(), dateTime.GetDay(), dateTime.GetHour(),
+ dateTime.GetMinute(), dateTime.GetSecond());
+ pParamsDict->SetNewFor<CPDF_String>("CreationDate", bsDateTime, false);
+
+ // Set the checksum of the new attachment in the dictionary.
+ pParamsDict->SetNewFor<CPDF_String>(
+ "CheckSum", CFXByteStringHexDecode(GenerateMD5Base16(contents, len)),
+ true);
+
+ // Create the file stream and have the filespec dictionary link to it.
+ std::unique_ptr<uint8_t, FxFreeDeleter> stream(FX_Alloc(uint8_t, len));
+ memcpy(stream.get(), contents, len);
+ CPDF_Stream* pFileStream = pDoc->NewIndirect<CPDF_Stream>(
+ std::move(stream), len, std::move(pFileStreamDict));
+ CPDF_Dictionary* pEFDict =
+ pFile->AsDictionary()->SetNewFor<CPDF_Dictionary>("EF");
+ pEFDict->SetNewFor<CPDF_Reference>("F", pDoc, pFileStream->GetObjNum());
+ return true;
+}
+
DLLEXPORT unsigned long STDCALL
FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,
void* buffer,