Add FPDFSignatureObj_GetByteRange() API

This follows the same pattern as FPDFSignatureObj_GetContents(), so the
client has to call this function twice, but allocation of the buffer
happens outside pdfium.

The length is the number of ints in the buffer, which feels
more natural than the underlying bytes.

Change-Id: Ib24c4e2ae79dc685d21fc0afca891f41ae078dde
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71690
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdf_signature.cpp b/fpdfsdk/fpdf_signature.cpp
index 1d9f76a..8d3a01f 100644
--- a/fpdfsdk/fpdf_signature.cpp
+++ b/fpdfsdk/fpdf_signature.cpp
@@ -77,3 +77,28 @@
 
   return contents_len;
 }
+
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,
+                              int* buffer,
+                              unsigned long length) {
+  CPDF_Dictionary* signature_dict = CPDFDictionaryFromFPDFSignature(signature);
+  if (!signature_dict)
+    return 0;
+
+  CPDF_Dictionary* value_dict = signature_dict->GetDictFor("V");
+  if (!value_dict)
+    return 0;
+
+  const CPDF_Array* byte_range = value_dict->GetArrayFor("ByteRange");
+  if (!byte_range)
+    return 0;
+
+  unsigned long byte_range_len = byte_range->size();
+  if (buffer && length >= byte_range_len) {
+    for (size_t i = 0; i < byte_range_len; ++i)
+      buffer[i] = byte_range->GetIntegerAt(i);
+  }
+
+  return byte_range_len;
+}
diff --git a/fpdfsdk/fpdf_signature_embeddertest.cpp b/fpdfsdk/fpdf_signature_embeddertest.cpp
index 6d88d8c..8a93916 100644
--- a/fpdfsdk/fpdf_signature_embeddertest.cpp
+++ b/fpdfsdk/fpdf_signature_embeddertest.cpp
@@ -65,3 +65,30 @@
   EXPECT_EQ('x', contents[0]);
   EXPECT_EQ('\0', contents[1]);
 }
+
+TEST_F(FPDFSignatureEmbedderTest, GetByteRange) {
+  ASSERT_TRUE(OpenDocument("two_signatures.pdf"));
+  FPDF_SIGNATURE signature = FPDF_GetSignatureObject(document(), 0);
+  EXPECT_NE(nullptr, signature);
+
+  // FPDFSignatureObj_GetByteRange() positive testing.
+  unsigned long size = FPDFSignatureObj_GetByteRange(signature, nullptr, 0);
+  const std::vector<int> kExpectedByteRange{0, 10, 30, 10};
+  ASSERT_EQ(kExpectedByteRange.size(), size);
+  std::vector<int> byte_range(size);
+  ASSERT_EQ(size,
+            FPDFSignatureObj_GetByteRange(signature, byte_range.data(), size));
+  ASSERT_EQ(kExpectedByteRange, byte_range);
+
+  // FPDFSignatureObj_GetByteRange() negative testing.
+  ASSERT_EQ(0U, FPDFSignatureObj_GetContents(nullptr, nullptr, 0));
+
+  byte_range.resize(2);
+  byte_range[0] = 0;
+  byte_range[1] = 1;
+  size = FPDFSignatureObj_GetByteRange(signature, byte_range.data(),
+                                       byte_range.size());
+  ASSERT_EQ(kExpectedByteRange.size(), size);
+  EXPECT_EQ(0, byte_range[0]);
+  EXPECT_EQ(1, byte_range[1]);
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index a7310b9..c82e22e 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -317,6 +317,7 @@
     CHK(FPDFText_GetTextIndexFromCharIndex);
 
     // fpdf_signature.h
+    CHK(FPDFSignatureObj_GetByteRange);
     CHK(FPDFSignatureObj_GetContents);
     CHK(FPDF_GetSignatureCount);
     CHK(FPDF_GetSignatureObject);
diff --git a/public/fpdf_signature.h b/public/fpdf_signature.h
index 6902602..439226d 100644
--- a/public/fpdf_signature.h
+++ b/public/fpdf_signature.h
@@ -53,6 +53,28 @@
                              void* buffer,
                              unsigned long length);
 
+// Experimental API.
+// Function: FPDFSignatureObj_GetByteRange
+//          Get the byte range of a signature object.
+// Parameters:
+//          signature   -   Handle to the signature object. Returned by
+//                          FPDF_GetSignatureObject().
+//          buffer      -   The address of a buffer that receives the
+//                          byte range.
+//          length      -   The size, in ints, of |buffer|.
+// Return value:
+//          Returns the number of ints in the byte range on
+//          success, 0 on error.
+//
+// |buffer| is an array of pairs of integers (starting byte offset,
+// length in bytes) that describes the exact byte range for the digest
+// calculation. If |length| is less than the returned length, or
+// |buffer| is NULL, |buffer| will not be modified.
+FPDF_EXPORT unsigned long FPDF_CALLCONV
+FPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,
+                              int* buffer,
+                              unsigned long length);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus