Add FPDF_GetSignatureObject() API
This builds on top of the recently added FPDF_GetSignatureCount() API.
The combination of the two allows iterating over all signature objects,
which adds the possibility to later add getter functions to access the
actual properties of the returned FPDF_SIGNATURE.
Change-Id: I46e822d2b9aa7511850acb353472cbf058c85a2a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/70990
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_helpers.h b/fpdfsdk/cpdfsdk_helpers.h
index 73ca946..9d47ad1 100644
--- a/fpdfsdk/cpdfsdk_helpers.h
+++ b/fpdfsdk/cpdfsdk_helpers.h
@@ -211,6 +211,11 @@
return reinterpret_cast<CPDFSDK_FormFillEnvironment*>(handle);
}
+inline FPDF_SIGNATURE FPDFSignatureFromCPDFDictionary(
+ CPDF_Dictionary* dictionary) {
+ return reinterpret_cast<FPDF_SIGNATURE>(dictionary);
+}
+
CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle);
ByteString ByteStringFromFPDFWideString(FPDF_WIDESTRING wide_string);
diff --git a/fpdfsdk/fpdf_signature.cpp b/fpdfsdk/fpdf_signature.cpp
index 0d898ef..7c1353f 100644
--- a/fpdfsdk/fpdf_signature.cpp
+++ b/fpdfsdk/fpdf_signature.cpp
@@ -8,31 +8,52 @@
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "fpdfsdk/cpdfsdk_helpers.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+std::vector<CPDF_Dictionary*> CollectSignatures(CPDF_Document* doc) {
+ std::vector<CPDF_Dictionary*> signatures;
+ CPDF_Dictionary* root = doc->GetRoot();
+ if (!root)
+ return signatures;
+
+ const CPDF_Dictionary* acro_form = root->GetDictFor("AcroForm");
+ if (!acro_form)
+ return signatures;
+
+ const CPDF_Array* fields = acro_form->GetArrayFor("Fields");
+ if (!fields)
+ return signatures;
+
+ CPDF_ArrayLocker locker(fields);
+ for (auto& field : locker) {
+ CPDF_Dictionary* field_dict = field->GetDict();
+ if (field_dict && field_dict->GetNameFor("FT") == "Sig")
+ signatures.push_back(field_dict);
+ }
+ return signatures;
+}
+
+} // namespace
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document) {
auto* doc = CPDFDocumentFromFPDFDocument(document);
if (!doc)
return -1;
- CPDF_Dictionary* root = doc->GetRoot();
- if (!root)
- return 0;
+ return pdfium::CollectionSize<int>(CollectSignatures(doc));
+}
- const CPDF_Dictionary* acro_form = root->GetDictFor("AcroForm");
- if (!acro_form)
- return 0;
+FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV
+FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index) {
+ auto* doc = CPDFDocumentFromFPDFDocument(document);
+ if (!doc)
+ return nullptr;
- const CPDF_Array* fields = acro_form->GetArrayFor("Fields");
- if (!fields)
- return 0;
+ std::vector<CPDF_Dictionary*> signatures = CollectSignatures(doc);
+ if (!pdfium::IndexInBounds(signatures, index))
+ return nullptr;
- int signature_count = 0;
- CPDF_ArrayLocker locker(fields);
- for (const auto& field : locker) {
- const CPDF_Dictionary* field_dict = field->GetDict();
- if (field_dict && field_dict->GetNameFor("FT") == "Sig")
- ++signature_count;
- }
-
- return signature_count;
+ return FPDFSignatureFromCPDFDictionary(signatures[index]);
}
diff --git a/fpdfsdk/fpdf_signature_embeddertest.cpp b/fpdfsdk/fpdf_signature_embeddertest.cpp
index fb8bb3a..851df00 100644
--- a/fpdfsdk/fpdf_signature_embeddertest.cpp
+++ b/fpdfsdk/fpdf_signature_embeddertest.cpp
@@ -19,3 +19,20 @@
// Provide no document.
EXPECT_EQ(-1, FPDF_GetSignatureCount(nullptr));
}
+
+TEST_F(FPDFSignatureEmbedderTest, GetSignatureObject) {
+ EXPECT_TRUE(OpenDocument("two_signatures.pdf"));
+ // Different, non-null signature objects are returned.
+ FPDF_SIGNATURE signature1 = FPDF_GetSignatureObject(document(), 0);
+ EXPECT_NE(nullptr, signature1);
+ FPDF_SIGNATURE signature2 = FPDF_GetSignatureObject(document(), 1);
+ EXPECT_NE(nullptr, signature2);
+ EXPECT_NE(signature1, signature2);
+
+ // Out of bounds.
+ EXPECT_EQ(nullptr, FPDF_GetSignatureObject(document(), -1));
+ EXPECT_EQ(nullptr, FPDF_GetSignatureObject(document(), 2));
+
+ // Provide no document.
+ EXPECT_EQ(nullptr, FPDF_GetSignatureObject(nullptr, 0));
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index d04d1f8..b0e4606 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -317,6 +317,7 @@
// fpdf_signature.h
CHK(FPDF_GetSignatureCount);
+ CHK(FPDF_GetSignatureObject);
// fpdf_structtree.h
CHK(FPDF_StructElement_CountChildren);
diff --git a/public/fpdf_signature.h b/public/fpdf_signature.h
index 7290bcb..df01a84 100644
--- a/public/fpdf_signature.h
+++ b/public/fpdf_signature.h
@@ -21,6 +21,19 @@
// Total number of signatures in the document on success, -1 on error.
FPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document);
+// Experimental API.
+// Function: FPDF_GetSignatureObject
+// Get the Nth signature of the document.
+// Parameters:
+// document - Handle to document. Returned by FPDF_LoadDocument().
+// index - Index into the array of signatures of the document.
+// Return value:
+// Returns the handle to the signature, or NULL on failure. The caller
+// does not take ownership of the returned FPDF_SIGNATURE. Instead, it
+// remains valid until FPDF_CloseDocument() is called for the document.
+FPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV
+FPDF_GetSignatureObject(FPDF_DOCUMENT document, int index);
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
diff --git a/public/fpdfview.h b/public/fpdfview.h
index debe083..3181df3 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -71,6 +71,7 @@
typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;
typedef void* FPDF_RECORDER; // Passed into skia.
typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;
+typedef struct fpdf_signature_t__* FPDF_SIGNATURE;
typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;
typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;
typedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;