Add new function `FPDFBookmark_GetCount()`

This may be used to determine the number of child items or the state of
a bookmark.

Bug: pdfium:1758
Change-Id: I96f5598aa68dbc19ea845f56962fb65fa9ecc477
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93630
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/AUTHORS b/AUTHORS
index 1b65598..0405d27 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -20,6 +20,7 @@
 Jiang Jiang <jiangj@opera.com>
 Ke Liu <stackexploit@gmail.com>
 Luật Nguyễn <manhluat93.php@gmail.com>
+Manuel Geißer <geisserml@gmail.com>
 Michael Doppler <m.doppler@gmail.com>
 Miklos Vajna <vmiklos@vmiklos.hu>
 Minh Trần <myoki.crystal@gmail.com>
diff --git a/core/fpdfdoc/cpdf_bookmark.cpp b/core/fpdfdoc/cpdf_bookmark.cpp
index 954831b..f91bce7 100644
--- a/core/fpdfdoc/cpdf_bookmark.cpp
+++ b/core/fpdfdoc/cpdf_bookmark.cpp
@@ -51,3 +51,7 @@
 CPDF_Action CPDF_Bookmark::GetAction() const {
   return CPDF_Action(m_pDict ? m_pDict->GetDictFor("A") : nullptr);
 }
+
+int CPDF_Bookmark::GetCount() const {
+  return m_pDict->GetIntegerFor("Count");
+}
diff --git a/core/fpdfdoc/cpdf_bookmark.h b/core/fpdfdoc/cpdf_bookmark.h
index 5b166a9..1cdcf9b 100644
--- a/core/fpdfdoc/cpdf_bookmark.h
+++ b/core/fpdfdoc/cpdf_bookmark.h
@@ -27,6 +27,7 @@
   WideString GetTitle() const;
   CPDF_Dest GetDest(CPDF_Document* pDocument) const;
   CPDF_Action GetAction() const;
+  int GetCount() const;
 
  private:
   RetainPtr<const CPDF_Dictionary> m_pDict;
diff --git a/fpdfsdk/fpdf_doc.cpp b/fpdfsdk/fpdf_doc.cpp
index 2751ca8..ab8fc03 100644
--- a/fpdfsdk/fpdf_doc.cpp
+++ b/fpdfsdk/fpdf_doc.cpp
@@ -111,6 +111,13 @@
   return Utf16EncodeMaybeCopyAndReturnLength(title, buffer, buflen);
 }
 
+FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark) {
+  if (!bookmark)
+    return 0;
+  CPDF_Bookmark cBookmark(CPDFDictionaryFromFPDFBookmark(bookmark));
+  return cBookmark.GetCount();
+}
+
 FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV
 FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title) {
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
diff --git a/fpdfsdk/fpdf_doc_embeddertest.cpp b/fpdfsdk/fpdf_doc_embeddertest.cpp
index 4e69a2c..5e5a722 100644
--- a/fpdfsdk/fpdf_doc_embeddertest.cpp
+++ b/fpdfsdk/fpdf_doc_embeddertest.cpp
@@ -477,6 +477,8 @@
   EXPECT_TRUE(child);
   EXPECT_EQ(34u, FPDFBookmark_GetTitle(child, buf, sizeof(buf)));
   EXPECT_EQ(L"A Good Beginning", GetPlatformWString(buf));
+  EXPECT_EQ(0, FPDFBookmark_GetCount(child));
+  EXPECT_EQ(0, FPDFBookmark_GetCount(nullptr));
 
   EXPECT_FALSE(FPDFBookmark_GetDest(document(), child));
   EXPECT_FALSE(FPDFBookmark_GetAction(child));
@@ -489,11 +491,13 @@
   EXPECT_EQ(24u, FPDFBookmark_GetTitle(sibling, buf, sizeof(buf)));
   EXPECT_EQ(L"Open Middle", GetPlatformWString(buf));
   EXPECT_TRUE(FPDFBookmark_GetAction(sibling));
+  EXPECT_EQ(1, FPDFBookmark_GetCount(sibling));
 
   FPDF_BOOKMARK sibling2 = FPDFBookmark_GetNextSibling(document(), sibling);
   EXPECT_TRUE(sibling2);
   EXPECT_EQ(42u, FPDFBookmark_GetTitle(sibling2, buf, sizeof(buf)));
   EXPECT_EQ(L"A Good Closed Ending", GetPlatformWString(buf));
+  EXPECT_EQ(-2, FPDFBookmark_GetCount(sibling2));
 
   EXPECT_EQ(nullptr, FPDFBookmark_GetNextSibling(document(), sibling2));
 
@@ -501,6 +505,7 @@
   EXPECT_TRUE(grand_child);
   EXPECT_EQ(46u, FPDFBookmark_GetTitle(grand_child, buf, sizeof(buf)));
   EXPECT_EQ(L"Open Middle Descendant", GetPlatformWString(buf));
+  EXPECT_EQ(0, FPDFBookmark_GetCount(grand_child));
   EXPECT_TRUE(FPDFBookmark_GetDest(document(), grand_child));
 
   EXPECT_FALSE(FPDFBookmark_GetNextSibling(document(), grand_child));
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 696d3a6..4e3627f 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -133,6 +133,7 @@
     CHK(FPDFAction_GetURIPath);
     CHK(FPDFBookmark_Find);
     CHK(FPDFBookmark_GetAction);
+    CHK(FPDFBookmark_GetCount);
     CHK(FPDFBookmark_GetDest);
     CHK(FPDFBookmark_GetFirstChild);
     CHK(FPDFBookmark_GetNextSibling);
diff --git a/public/fpdf_doc.h b/public/fpdf_doc.h
index df453ad..977e1c9 100644
--- a/public/fpdf_doc.h
+++ b/public/fpdf_doc.h
@@ -98,6 +98,18 @@
                       void* buffer,
                       unsigned long buflen);
 
+// Experimental API.
+// Get the number of chlidren of |bookmark|.
+//
+//   bookmark - handle to the bookmark.
+//
+// Returns a signed integer that represents the number of sub-items the given
+// bookmark has. If the value is positive, child items shall be shown by default
+// (open state). If the value is negative, child items shall be hidden by
+// default (closed state). Please refer to PDF 32000-1:2008, Table 153.
+// Returns 0 if the bookmark has no children or is invalid.
+FPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark);
+
 // Find the bookmark with |title| in |document|.
 //
 //   document - handle to the document.