[fpdf_structtree] Support references for attribute list/number
PDF software such as Adobe Acrobat Pro sometimes uses references for attribute lists (instead of array or dictionary). Similarly, attributes themselves (e.g. "ColSpan" for a TD or TH cell) sometimes use references as well.
Change-Id: I1bd8f56348ba48d84b72179c86db688304660682
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/110850
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Ilaï Deutel <idtl@google.com>
diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp
index dc68239..4817f47 100644
--- a/fpdfsdk/fpdf_structtree.cpp
+++ b/fpdfsdk/fpdf_structtree.cpp
@@ -135,6 +135,10 @@
if (!elem)
return -1;
RetainPtr<const CPDF_Object> attr_obj = elem->GetA();
+ if (!attr_obj) {
+ return -1;
+ }
+ attr_obj = attr_obj->GetDirect();
if (!attr_obj)
return -1;
if (attr_obj->IsArray())
@@ -154,6 +158,10 @@
if (!attr_obj)
return nullptr;
+ attr_obj = attr_obj->GetDirect();
+ if (!attr_obj) {
+ return nullptr;
+ }
if (attr_obj->IsDictionary()) {
return index == 0 ? FPDFStructElementAttrFromCPDFDictionary(
attr_obj->AsDictionary())
@@ -353,7 +361,7 @@
if (!dict)
return false;
- RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name);
+ RetainPtr<const CPDF_Object> obj = dict->GetDirectObjectFor(name);
if (!obj || !obj->IsNumber())
return false;
diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp
index 1ee1612..2704887 100644
--- a/fpdfsdk/fpdf_structtree_embeddertest.cpp
+++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp
@@ -648,11 +648,12 @@
FPDF_STRUCTELEMENT td = FPDF_StructElement_GetChildAtIndex(tr, 1);
ASSERT_TRUE(td);
{
+ // Test counting and obtaining attributes via reference
ASSERT_EQ(1, FPDF_StructElement_GetAttributeCount(td));
FPDF_STRUCTELEMENT_ATTR attr =
FPDF_StructElement_GetAttributeAtIndex(td, 0);
ASSERT_TRUE(attr);
- ASSERT_EQ(3, FPDF_StructElement_Attr_GetCount(attr));
+ ASSERT_EQ(4, FPDF_StructElement_Attr_GetCount(attr));
// Test string and blob type
{
char buffer[16] = {};
@@ -696,6 +697,23 @@
FPDF_StructElement_Attr_GetBooleanValue(attr, buffer, &val));
EXPECT_TRUE(val);
}
+
+ // Test reference to number
+ {
+ char buffer[16] = {};
+ unsigned long out_len = ULONG_MAX;
+ ASSERT_TRUE(FPDF_StructElement_Attr_GetName(
+ attr, 3, buffer, sizeof(buffer), &out_len));
+ EXPECT_EQ(8U, out_len);
+ EXPECT_STREQ("RowSpan", buffer);
+
+ EXPECT_EQ(FPDF_OBJECT_REFERENCE,
+ FPDF_StructElement_Attr_GetType(attr, buffer));
+ float val;
+ ASSERT_TRUE(
+ FPDF_StructElement_Attr_GetNumberValue(attr, buffer, &val));
+ EXPECT_FLOAT_EQ(3, val);
+ }
}
}
}
diff --git a/testing/resources/tagged_table.in b/testing/resources/tagged_table.in
index ee298c5..6e2ddc0 100644
--- a/testing/resources/tagged_table.in
+++ b/testing/resources/tagged_table.in
@@ -203,14 +203,22 @@
/S /TD
/P 13 0 R
/Pg 3 0 R
- /A [<<
- /O /Table
- /ColProp (Sum)
- /CurUSD true
- >>]
+ /A 18 0 R
/ID (node18)
>>
endobj
+{{object 18 0}} [
+ <<
+ /O /Table
+ /ColProp (Sum)
+ /CurUSD true
+ /RowSpan 19 0 R
+ >>
+]
+endobj
+{{object 19 0}}
+ 3
+endobj
{{xref}}
{{trailer}}
{{startxref}}
diff --git a/testing/resources/tagged_table.pdf b/testing/resources/tagged_table.pdf
index 4428682..6e2bf9e 100644
--- a/testing/resources/tagged_table.pdf
+++ b/testing/resources/tagged_table.pdf
@@ -204,16 +204,24 @@
/S /TD
/P 13 0 R
/Pg 3 0 R
- /A [<<
- /O /Table
- /ColProp (Sum)
- /CurUSD true
- >>]
+ /A 18 0 R
/ID (node18)
>>
endobj
+18 0 obj [
+ <<
+ /O /Table
+ /ColProp (Sum)
+ /CurUSD true
+ /RowSpan 19 0 R
+ >>
+]
+endobj
+19 0 obj
+ 3
+endobj
xref
-0 18
+0 20
0000000000 65535 f
0000000015 00000 n
0000000145 00000 n
@@ -232,10 +240,12 @@
0000002276 00000 n
0000002366 00000 n
0000002513 00000 n
+0000002615 00000 n
+0000002715 00000 n
trailer <<
/Root 1 0 R
- /Size 18
+ /Size 20
>>
startxref
-2683
+2735
%%EOF