diff options
author | Jane Liu <janeliulwq@google.com> | 2017-07-24 16:40:54 -0400 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-07-24 21:19:22 +0000 |
commit | 54a4214c86bc790cc2a3ae454b1aa709e868fa1a (patch) | |
tree | ebd92341381e3a16d386caf5280bc7626925b910 /fpdfsdk/fpdfattachment.cpp | |
parent | 6a388c1595522e26a633fbed1022752f4c80ac0c (diff) | |
download | pdfium-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.cpp | 146 |
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, |