summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJane Liu <janeliulwq@google.com>2017-07-18 10:15:16 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-07-19 13:55:30 +0000
commit18ae06d9ae493276b3ddcd37eb19de7aeba1a0e8 (patch)
treecfe59580602328796f2931506a591f2cf655c479
parent0add284c1a2b3bee022bef34c7efddcb304f2e21 (diff)
downloadpdfium-18ae06d9ae493276b3ddcd37eb19de7aeba1a0e8.tar.xz
Basic APIs and tests for extracting attachments
1. Added API for extracting attachment properties and data. * Expanded the embedder test to cover all the new APIs. Bug=pdfium:174 Change-Id: I09bffd412410e9aea45faca442d2b72eefafef4e Reviewed-on: https://pdfium-review.googlesource.com/7790 Reviewed-by: dsinclair <dsinclair@chromium.org> Commit-Queue: dsinclair <dsinclair@chromium.org>
-rw-r--r--core/fpdfapi/page/cpdf_streamparser.cpp35
-rw-r--r--core/fpdfapi/page/cpdf_streamparser.h9
-rw-r--r--fpdfsdk/fpdfannot.cpp15
-rw-r--r--fpdfsdk/fpdfattachment.cpp120
-rw-r--r--fpdfsdk/fpdfattachment_embeddertest.cpp69
-rw-r--r--fpdfsdk/fpdfdoc.cpp10
-rw-r--r--fpdfsdk/fpdfview.cpp20
-rw-r--r--fpdfsdk/fpdfview_c_api_test.c7
-rw-r--r--fpdfsdk/fsdk_define.h8
-rw-r--r--public/fpdf_annot.h11
-rw-r--r--public/fpdf_attachment.h85
-rw-r--r--public/fpdfview.h13
12 files changed, 324 insertions, 78 deletions
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index 37ab857816..964d600b3d 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -60,14 +60,17 @@ uint32_t DecodeAllScanlines(std::unique_ptr<CCodec_ScanlineDecoder> pDecoder,
return pDecoder->GetSrcOffset();
}
-uint32_t PDF_DecodeInlineStream(const uint8_t* src_buf,
- uint32_t limit,
- int width,
- int height,
- const CFX_ByteString& decoder,
- CPDF_Dictionary* pParam,
- uint8_t** dest_buf,
- uint32_t* dest_size) {
+} // namespace
+
+// Static
+uint32_t CPDF_StreamParser::DecodeInlineStream(const uint8_t* src_buf,
+ uint32_t limit,
+ int width,
+ int height,
+ const CFX_ByteString& decoder,
+ CPDF_Dictionary* pParam,
+ uint8_t** dest_buf,
+ uint32_t* dest_size) {
if (decoder == "CCITTFaxDecode" || decoder == "CCF") {
std::unique_ptr<CCodec_ScanlineDecoder> pDecoder =
FPDFAPI_CreateFaxDecoder(src_buf, limit, width, height, pParam);
@@ -99,22 +102,14 @@ uint32_t PDF_DecodeInlineStream(const uint8_t* src_buf,
return 0xFFFFFFFF;
}
-} // namespace
-
CPDF_StreamParser::CPDF_StreamParser(const uint8_t* pData, uint32_t dwSize)
- : m_pBuf(pData),
- m_Size(dwSize),
- m_Pos(0),
- m_pPool(nullptr) {}
+ : m_pBuf(pData), m_Size(dwSize), m_Pos(0), m_pPool(nullptr) {}
CPDF_StreamParser::CPDF_StreamParser(
const uint8_t* pData,
uint32_t dwSize,
const CFX_WeakPtr<CFX_ByteStringPool>& pPool)
- : m_pBuf(pData),
- m_Size(dwSize),
- m_Pos(0),
- m_pPool(pPool) {}
+ : m_pBuf(pData), m_Size(dwSize), m_Pos(0), m_pPool(pPool) {}
CPDF_StreamParser::~CPDF_StreamParser() {}
@@ -193,8 +188,8 @@ std::unique_ptr<CPDF_Stream> CPDF_StreamParser::ReadInlineStream(
uint8_t* pIgnore = nullptr;
uint32_t dwDestSize = OrigSize;
dwStreamSize =
- PDF_DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height,
- Decoder, pParam, &pIgnore, &dwDestSize);
+ DecodeInlineStream(m_pBuf + m_Pos, m_Size - m_Pos, width, height,
+ Decoder, pParam, &pIgnore, &dwDestSize);
FX_Free(pIgnore);
if (static_cast<int>(dwStreamSize) < 0)
return nullptr;
diff --git a/core/fpdfapi/page/cpdf_streamparser.h b/core/fpdfapi/page/cpdf_streamparser.h
index fdc418c634..9f9a8eaf12 100644
--- a/core/fpdfapi/page/cpdf_streamparser.h
+++ b/core/fpdfapi/page/cpdf_streamparser.h
@@ -21,6 +21,15 @@ class CPDF_StreamParser {
public:
enum SyntaxType { EndOfData, Number, Keyword, Name, Others };
+ static uint32_t DecodeInlineStream(const uint8_t* src_buf,
+ uint32_t limit,
+ int width,
+ int height,
+ const CFX_ByteString& decoder,
+ CPDF_Dictionary* pParam,
+ uint8_t** dest_buf,
+ uint32_t* dest_size);
+
CPDF_StreamParser(const uint8_t* pData, uint32_t dwSize);
CPDF_StreamParser(const uint8_t* pData,
uint32_t dwSize,
diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp
index 412c80b5de..1c4345ab52 100644
--- a/fpdfsdk/fpdfannot.cpp
+++ b/fpdfsdk/fpdfannot.cpp
@@ -170,10 +170,6 @@ bool HasAPStream(const CPDF_Dictionary* pAnnotDict) {
return !!FPDFDOC_GetAnnotAP(pAnnotDict, CPDF_Annot::AppearanceMode::Normal);
}
-CFX_ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING text) {
- return CFX_WideString::FromUTF16LE(text, CFX_WideString::WStringLength(text))
- .UTF8Encode();
-}
void UpdateContentStream(CPDF_Form* pForm, CPDF_Stream* pStream) {
ASSERT(pForm);
ASSERT(pStream);
@@ -760,14 +756,9 @@ DLLEXPORT unsigned long STDCALL FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
if (!pAnnotDict)
return 0;
- CFX_ByteString contents =
- pAnnotDict->GetUnicodeTextFor(CFXByteStringFromFPDFWideString(key))
- .UTF16LE_Encode();
- unsigned long len = contents.GetLength();
- if (buffer && buflen >= len)
- memcpy(buffer, contents.c_str(), len);
-
- return len;
+ return Utf16EncodeMaybeCopyAndReturnLength(
+ pAnnotDict->GetUnicodeTextFor(CFXByteStringFromFPDFWideString(key)),
+ buffer, buflen);
}
DLLEXPORT int STDCALL FPDFAnnot_GetFlags(FPDF_ANNOTATION annot) {
diff --git a/fpdfsdk/fpdfattachment.cpp b/fpdfsdk/fpdfattachment.cpp
index e07d15b0c8..337ab35e0f 100644
--- a/fpdfsdk/fpdfattachment.cpp
+++ b/fpdfsdk/fpdfattachment.cpp
@@ -4,7 +4,10 @@
#include "public/fpdf_attachment.h"
+#include "core/fpdfapi/page/cpdf_streamparser.h"
#include "core/fpdfapi/parser/cpdf_document.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 "fpdfsdk/fsdk_define.h"
@@ -17,28 +20,119 @@ DLLEXPORT int STDCALL FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document) {
return CPDF_NameTree(pDoc, "EmbeddedFiles").GetCount();
}
-DLLEXPORT unsigned long STDCALL
-FPDFDoc_GetAttachmentName(FPDF_DOCUMENT document,
- int index,
- void* buffer,
- unsigned long buflen) {
+DLLEXPORT FPDF_ATTACHMENT STDCALL FPDFDoc_GetAttachment(FPDF_DOCUMENT document,
+ int index) {
CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
if (!pDoc || index < 0)
- return 0;
+ return nullptr;
CPDF_NameTree nameTree(pDoc, "EmbeddedFiles");
if (static_cast<size_t>(index) >= nameTree.GetCount())
- return 0;
+ return nullptr;
CFX_ByteString csName;
- CPDF_Object* pFile = nameTree.LookupValueAndName(index, &csName);
+ return nameTree.LookupValueAndName(index, &csName);
+}
+
+DLLEXPORT unsigned long STDCALL
+FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,
+ void* buffer,
+ unsigned long buflen) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+ if (!pFile)
+ return 0;
+
+ return Utf16EncodeMaybeCopyAndReturnLength(CPDF_FileSpec(pFile).GetFileName(),
+ buffer, buflen);
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment,
+ FPDF_WIDESTRING key) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+ if (!pFile)
+ return 0;
+
+ CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+ if (!pParamsDict)
+ return 0;
+
+ return pParamsDict->KeyExist(CFXByteStringFromFPDFWideString(key));
+}
+
+DLLEXPORT FPDF_OBJECT_TYPE STDCALL
+FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_WIDESTRING key) {
+ if (!FPDFAttachment_HasKey(attachment, key))
+ return FPDF_OBJECT_UNKNOWN;
+
+ CPDF_Object* pObj = CPDF_FileSpec(CPDFObjectFromFPDFAttachment(attachment))
+ .GetParamsDict()
+ ->GetObjectFor(CFXByteStringFromFPDFWideString(key));
+ if (!pObj)
+ return FPDF_OBJECT_UNKNOWN;
+
+ return pObj->GetType();
+}
+
+DLLEXPORT unsigned long STDCALL
+FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
+ FPDF_WIDESTRING key,
+ void* buffer,
+ unsigned long buflen) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
+ if (!pFile)
+ return 0;
+
+ CPDF_Dictionary* pParamsDict = CPDF_FileSpec(pFile).GetParamsDict();
+ if (!pParamsDict)
+ return 0;
+
+ CFX_ByteString bsKey = CFXByteStringFromFPDFWideString(key);
+ CFX_WideString value = pParamsDict->GetUnicodeTextFor(bsKey);
+ if (bsKey == "CheckSum") {
+ CPDF_String* stringValue = pParamsDict->GetObjectFor(bsKey)->AsString();
+ if (stringValue->IsHex()) {
+ value =
+ CPDF_String(nullptr, PDF_EncodeString(stringValue->GetString(), true),
+ false)
+ .GetUnicodeText();
+ }
+ }
+
+ return Utf16EncodeMaybeCopyAndReturnLength(value, buffer, buflen);
+}
+
+DLLEXPORT unsigned long STDCALL
+FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,
+ void* buffer,
+ unsigned long buflen) {
+ CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
if (!pFile)
return 0;
- CFX_ByteString name = CPDF_FileSpec(pFile).GetFileName().UTF16LE_Encode();
- unsigned long len = name.GetLength();
- if (buffer && buflen >= len)
- memcpy(buffer, name.c_str(), len);
+ CPDF_Stream* pFileStream = CPDF_FileSpec(pFile).GetFileStream();
+ if (!pFileStream)
+ return 0;
+
+ uint8_t* data = pFileStream->GetRawData();
+ uint32_t len = pFileStream->GetRawSize();
+ CPDF_Dictionary* pFileDict = pFileStream->GetDict();
+ if (!pFileDict || pFileDict->GetStringFor("Filter").IsEmpty()) {
+ if (buffer && buflen >= len)
+ memcpy(buffer, data, len);
+
+ return len;
+ }
+
+ // Decode the stream if a stream filter is specified.
+ uint8_t* decodedData = nullptr;
+ uint32_t decodedLen = 0;
+ CPDF_StreamParser::DecodeInlineStream(
+ data, len, pFileDict->GetIntegerFor("Width"),
+ pFileDict->GetIntegerFor("Height"), pFileDict->GetStringFor("Filter"),
+ pFileDict->GetDictFor("DecodeParms"), &decodedData, &decodedLen);
+ if (buffer && buflen >= decodedLen)
+ memcpy(buffer, decodedData, decodedLen);
- return len;
+ FX_Free(decodedData);
+ return decodedLen;
}
diff --git a/fpdfsdk/fpdfattachment_embeddertest.cpp b/fpdfsdk/fpdfattachment_embeddertest.cpp
index 2cbda8a429..d873d9b5ce 100644
--- a/fpdfsdk/fpdfattachment_embeddertest.cpp
+++ b/fpdfsdk/fpdfattachment_embeddertest.cpp
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "public/fpdf_attachment.h"
+#include "public/fpdfview.h"
#include "testing/embedder_test.h"
class FPDFAttachmentEmbeddertest : public EmbedderTest {};
@@ -12,11 +13,75 @@ TEST_F(FPDFAttachmentEmbeddertest, ExtractAttachments) {
ASSERT_TRUE(OpenDocument("embedded_attachments.pdf"));
EXPECT_EQ(2, FPDFDoc_GetAttachmentCount(document()));
+ // Retrieve the first attachment.
+ FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(document(), 0);
+ ASSERT_TRUE(attachment);
+
// Check that the name of the first attachment is correct.
- unsigned long len = FPDFDoc_GetAttachmentName(document(), 0, nullptr, 0);
+ unsigned long len = FPDFAttachment_GetName(attachment, nullptr, 0);
std::vector<char> buf(len);
- EXPECT_EQ(12u, FPDFDoc_GetAttachmentName(document(), 0, buf.data(), len));
+ EXPECT_EQ(12u, FPDFAttachment_GetName(attachment, buf.data(), len));
EXPECT_STREQ(L"1.txt",
GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
.c_str());
+
+ // Check that the content of the first attachment is correct.
+ len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+ buf.clear();
+ buf.resize(len);
+ ASSERT_EQ(4u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+ EXPECT_EQ(std::string("test"), std::string(buf.data(), 4));
+
+ // Check that a non-existent key does not exist.
+ EXPECT_FALSE(
+ FPDFAttachment_HasKey(attachment, GetFPDFWideString(L"none").get()));
+
+ // Check that the string value of a non-string dictionary entry is empty.
+ std::unique_ptr<unsigned short, pdfium::FreeDeleter> size_key =
+ GetFPDFWideString(L"Size");
+ EXPECT_EQ(FPDF_OBJECT_NUMBER,
+ FPDFAttachment_GetValueType(attachment, size_key.get()));
+ EXPECT_EQ(2u, FPDFAttachment_GetStringValue(attachment, size_key.get(),
+ nullptr, 0));
+
+ // Check that the creation date of the first attachment is correct.
+ std::unique_ptr<unsigned short, pdfium::FreeDeleter> date_key =
+ GetFPDFWideString(L"CreationDate");
+ len = FPDFAttachment_GetStringValue(attachment, date_key.get(), nullptr, 0);
+ buf.clear();
+ buf.resize(len);
+ EXPECT_EQ(48u, FPDFAttachment_GetStringValue(attachment, date_key.get(),
+ buf.data(), len));
+ EXPECT_STREQ(L"D:20170712214438-07'00'",
+ GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
+ .c_str());
+
+ // Retrieve the second attachment.
+ attachment = FPDFDoc_GetAttachment(document(), 1);
+ ASSERT_TRUE(attachment);
+
+ // Retrieve the second attachment file.
+ len = FPDFAttachment_GetFile(attachment, nullptr, 0);
+ buf.clear();
+ buf.resize(len);
+ EXPECT_EQ(5869u, FPDFAttachment_GetFile(attachment, buf.data(), len));
+
+ // Check that the calculated checksum of the file data matches expectation.
+ const char kCheckSum[] = "72afcddedf554dda63c0c88e06f1ce18";
+ const wchar_t kCheckSumW[] = L"<72AFCDDEDF554DDA63C0C88E06F1CE18>";
+ const std::string generated_checksum =
+ GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()), len);
+ EXPECT_EQ(kCheckSum, generated_checksum);
+
+ // Check that the stored checksum matches expectation.
+ std::unique_ptr<unsigned short, pdfium::FreeDeleter> checksum_key =
+ GetFPDFWideString(L"CheckSum");
+ len =
+ FPDFAttachment_GetStringValue(attachment, checksum_key.get(), nullptr, 0);
+ buf.clear();
+ buf.resize(len);
+ EXPECT_EQ(70u, FPDFAttachment_GetStringValue(attachment, checksum_key.get(),
+ buf.data(), len));
+ EXPECT_EQ(kCheckSumW,
+ GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data())));
}
diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp
index 7be53a6554..b6088604fd 100644
--- a/fpdfsdk/fpdfdoc.cpp
+++ b/fpdfsdk/fpdfdoc.cpp
@@ -60,16 +60,6 @@ CPDF_LinkList* GetLinkList(CPDF_Page* page) {
return pHolder->get();
}
-unsigned long Utf16EncodeMaybeCopyAndReturnLength(const CFX_WideString& text,
- void* buffer,
- unsigned long buflen) {
- CFX_ByteString encodedText = text.UTF16LE_Encode();
- unsigned long len = encodedText.GetLength();
- if (buffer && len <= buflen)
- memcpy(buffer, encodedText.c_str(), len);
- return len;
-}
-
} // namespace
DLLEXPORT FPDF_BOOKMARK STDCALL
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index 2e52ad6487..06e72b3a71 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -320,10 +320,30 @@ CPDF_PageObject* CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object) {
return static_cast<CPDF_PageObject*>(page_object);
}
+CPDF_Object* CPDFObjectFromFPDFAttachment(FPDF_ATTACHMENT attachment) {
+ return static_cast<CPDF_Object*>(attachment);
+}
+
+CFX_ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string) {
+ return CFX_WideString::FromUTF16LE(wide_string,
+ CFX_WideString::WStringLength(wide_string))
+ .UTF8Encode();
+}
+
CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap) {
return static_cast<CFX_DIBitmap*>(bitmap);
}
+unsigned long Utf16EncodeMaybeCopyAndReturnLength(const CFX_WideString& text,
+ void* buffer,
+ unsigned long buflen) {
+ CFX_ByteString encodedText = text.UTF16LE_Encode();
+ unsigned long len = encodedText.GetLength();
+ if (buffer && len <= buflen)
+ memcpy(buffer, encodedText.c_str(), len);
+ return len;
+}
+
CFX_RetainPtr<IFX_SeekableReadStream> MakeSeekableReadStream(
FPDF_FILEACCESS* pFileAccess) {
return pdfium::MakeRetain<CPDF_CustomAccess>(pFileAccess);
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 2fcaf7455f..6753e66c52 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -64,7 +64,12 @@ int CheckPDFiumCApi() {
// fpdf_attachment.h
CHK(FPDFDoc_GetAttachmentCount);
- CHK(FPDFDoc_GetAttachmentName);
+ CHK(FPDFDoc_GetAttachment);
+ CHK(FPDFAttachment_GetName);
+ CHK(FPDFAttachment_HasKey);
+ CHK(FPDFAttachment_GetValueType);
+ CHK(FPDFAttachment_GetStringValue);
+ CHK(FPDFAttachment_GetFile);
// fpdf_dataavail.h
CHK(FPDFAvail_Create);
diff --git a/fpdfsdk/fsdk_define.h b/fpdfsdk/fsdk_define.h
index 4cfe3442ac..610b854a9d 100644
--- a/fpdfsdk/fsdk_define.h
+++ b/fpdfsdk/fsdk_define.h
@@ -67,8 +67,16 @@ CPDF_PathObject* CPDFPathObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object);
CPDF_PageObject* CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object);
+CPDF_Object* CPDFObjectFromFPDFAttachment(FPDF_ATTACHMENT attachment);
+
+CFX_ByteString CFXByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string);
+
CFX_DIBitmap* CFXBitmapFromFPDFBitmap(FPDF_BITMAP bitmap);
+unsigned long Utf16EncodeMaybeCopyAndReturnLength(const CFX_WideString& text,
+ void* buffer,
+ unsigned long buflen);
+
void FSDK_SetSandBoxPolicy(FPDF_DWORD policy, FPDF_BOOL enable);
FPDF_BOOL FSDK_IsSandBoxPolicyEnabled(FPDF_DWORD policy);
void FPDF_RenderPage_Retail(CPDF_PageRenderContext* pContext,
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index e6c33a59eb..5076470627 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -55,17 +55,6 @@ extern "C" {
#define FPDF_ANNOT_FLAG_LOCKED (1 << 7)
#define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8)
-#define FPDF_OBJECT_UNKNOWN 0
-#define FPDF_OBJECT_BOOLEAN 1
-#define FPDF_OBJECT_NUMBER 2
-#define FPDF_OBJECT_STRING 3
-#define FPDF_OBJECT_NAME 4
-#define FPDF_OBJECT_ARRAY 5
-#define FPDF_OBJECT_DICTIONARY 6
-#define FPDF_OBJECT_STREAM 7
-#define FPDF_OBJECT_NULLOBJ 8
-#define FPDF_OBJECT_REFERENCE 9
-
typedef enum FPDFANNOT_COLORTYPE {
FPDFANNOT_COLORTYPE_Color = 0,
FPDFANNOT_COLORTYPE_InteriorColor
diff --git a/public/fpdf_attachment.h b/public/fpdf_attachment.h
index 07fdff5a9e..2c40992760 100644
--- a/public/fpdf_attachment.h
+++ b/public/fpdf_attachment.h
@@ -21,21 +21,88 @@ extern "C" {
DLLEXPORT int STDCALL FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document);
// Experimental API.
-// Get the name of the embedded file at |index| in |document|. |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.
+// Get the embedded attachment at |index| in |document|. Note that the returned
+// attachment handle is only valid while |document| is open.
//
// document - handle to a document.
// index - the index of the requested embedded file.
-// buffer - buffer for holding the file name, encoded in UTF16-LE.
-// buflen - length of the buffer.
+//
+// Returns the handle to the attachment object, or NULL on failure.
+DLLEXPORT FPDF_ATTACHMENT STDCALL FPDFDoc_GetAttachment(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.
+//
+// attachment - handle to an attachment.
+// buffer - buffer for holding the file name, encoded in UTF16-LE.
+// buflen - length of the buffer.
//
// Returns the length of the file name.
DLLEXPORT unsigned long STDCALL
-FPDFDoc_GetAttachmentName(FPDF_DOCUMENT document,
- int index,
- void* buffer,
- unsigned long buflen);
+FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,
+ void* buffer,
+ unsigned long buflen);
+
+// Experimental API.
+// Check if the params dictionary of |attachment| has |key| as a key.
+//
+// attachment - handle to an attachment.
+// key - the key to look for.
+//
+// Returns true if |key| exists.
+DLLEXPORT FPDF_BOOL STDCALL FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment,
+ FPDF_WIDESTRING key);
+
+// Experimental API.
+// Get the type of the value corresponding to |key| in the params dictionary of
+// the embedded |attachment|.
+//
+// attachment - handle to an attachment.
+// key - the key to look for.
+//
+// Returns the type of the dictionary value.
+DLLEXPORT FPDF_OBJECT_TYPE STDCALL
+FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_WIDESTRING key);
+
+// Experimental API.
+// Get the string value corresponding to |key| in the params dictionary of the
+// embedded file |attachment|. |buffer| is only modified if |buflen| is longer
+// than the length of the string value. Note that if |key| does not exist in the
+// dictionary or if |key|'s corresponding value in the dictionary is not a
+// string (i.e. the value is not of type FPDF_OBJECT_STRING or
+// FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the
+// return value would be 2. On other errors, nothing would be added to |buffer|
+// and the return value would be 0.
+//
+// attachment - handle to an attachment.
+// key - the key to the requested string value.
+// buffer - buffer for holding the file's date string encoded in UTF16-LE.
+// buflen - length of the buffer.
+//
+// Returns the length of the dictionary value string.
+DLLEXPORT unsigned long STDCALL
+FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
+ FPDF_WIDESTRING key,
+ void* buffer,
+ unsigned long buflen);
+
+// Experimental API.
+// Get the file data of |attachment|. |buffer| is only modified if |buflen| is
+// longer than the length of the file. On errors, |buffer| is unmodified and the
+// returned length is 0.
+//
+// attachment - handle to an attachment.
+// buffer - buffer for holding the file's data in raw bytes.
+// buflen - length of the buffer.
+//
+// Returns the length of the file.
+DLLEXPORT unsigned long STDCALL
+FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,
+ void* buffer,
+ unsigned long buflen);
#ifdef __cplusplus
} // extern "C"
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 95900f3848..55897eb467 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -20,9 +20,22 @@
#define PDF_USE_XFA
#endif // PDF_ENABLE_XFA
+// PDF object types
+#define FPDF_OBJECT_UNKNOWN 0
+#define FPDF_OBJECT_BOOLEAN 1
+#define FPDF_OBJECT_NUMBER 2
+#define FPDF_OBJECT_STRING 3
+#define FPDF_OBJECT_NAME 4
+#define FPDF_OBJECT_ARRAY 5
+#define FPDF_OBJECT_DICTIONARY 6
+#define FPDF_OBJECT_STREAM 7
+#define FPDF_OBJECT_NULLOBJ 8
+#define FPDF_OBJECT_REFERENCE 9
+
// PDF types
typedef void* FPDF_ACTION;
typedef void* FPDF_ANNOTATION;
+typedef void* FPDF_ATTACHMENT;
typedef void* FPDF_BITMAP;
typedef void* FPDF_BOOKMARK;
typedef void* FPDF_CLIPPATH;