Add more ParserXRefTest test cases for /Index
Add test cases for:
- A perfectly valid /Index
- An /Index that specifies an object twice
- An /Index that have its objects out of order
Change-Id: I76f289aa4d32707b48db974d69b667ee2391bc13
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/108813
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
index 1872e8d..f8d42a8 100644
--- a/core/fpdfapi/parser/cpdf_parser_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
@@ -652,3 +652,131 @@
EXPECT_THAT(objects_info, ElementsAre(Pair(0, expected_result[0]),
Pair(1, expected_result[1])));
}
+
+TEST_F(ParserXRefTest, XrefWithValidIndex) {
+ // The /Index specifies objects (2), (4, 5), (80, 81, 82).
+ const unsigned char kData[] =
+ "%PDF1-7\n%\xa0\xf2\xa4\xf4\n"
+ "7 0 obj <<\n"
+ " /Filter /ASCIIHexDecode\n"
+ " /Root 1 0 R\n"
+ " /Size 83\n"
+ " /Index [2 1 4 2 80 3]\n"
+ " /W [1 1 1]\n"
+ ">>\n"
+ "stream\n"
+ "01 00 00\n"
+ "01 0F 00\n"
+ "01 12 00\n"
+ "01 20 00\n"
+ "01 22 00\n"
+ "01 25 00\n"
+ "endstream\n"
+ "endobj\n"
+ "startxref\n"
+ "14\n"
+ "%%EOF\n";
+
+ ASSERT_TRUE(parser().InitTestFromBuffer(kData));
+ EXPECT_EQ(CPDF_Parser::SUCCESS, parser().StartParseInternal());
+ EXPECT_FALSE(parser().xref_table_rebuilt());
+ ASSERT_TRUE(parser().GetCrossRefTable());
+ const auto& objects_info = parser().GetCrossRefTable()->objects_info();
+
+ CPDF_Parser::ObjectInfo expected_result[6];
+ expected_result[0].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[0].pos = 0;
+ expected_result[1].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[1].pos = 15;
+ expected_result[2].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[2].pos = 18;
+ expected_result[3].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[3].pos = 32;
+ expected_result[4].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[4].pos = 34;
+ expected_result[5].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[5].pos = 37;
+ EXPECT_THAT(
+ objects_info,
+ ElementsAre(Pair(2, expected_result[0]), Pair(4, expected_result[1]),
+ Pair(5, expected_result[2]), Pair(80, expected_result[3]),
+ Pair(81, expected_result[4]), Pair(82, expected_result[5])));
+}
+
+TEST_F(ParserXRefTest, XrefIndexWithRepeatedObject) {
+ // The /Index specifies objects (2, 3), (3). AKA the sub-sections overlap.
+ const unsigned char kData[] =
+ "%PDF1-7\n%\xa0\xf2\xa4\xf4\n"
+ "7 0 obj <<\n"
+ " /Filter /ASCIIHexDecode\n"
+ " /Root 1 0 R\n"
+ " /Size 4\n"
+ " /Index [2 2 3 1]\n"
+ " /W [1 1 1]\n"
+ ">>\n"
+ "stream\n"
+ "01 00 00\n"
+ "01 0F 00\n"
+ "01 12 00\n"
+ "endstream\n"
+ "endobj\n"
+ "startxref\n"
+ "14\n"
+ "%%EOF\n";
+
+ ASSERT_TRUE(parser().InitTestFromBuffer(kData));
+ EXPECT_EQ(CPDF_Parser::SUCCESS, parser().StartParseInternal());
+ EXPECT_FALSE(parser().xref_table_rebuilt());
+ ASSERT_TRUE(parser().GetCrossRefTable());
+ const auto& objects_info = parser().GetCrossRefTable()->objects_info();
+
+ CPDF_Parser::ObjectInfo expected_result[2];
+ expected_result[0].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[0].pos = 0;
+ expected_result[1].type = CPDF_Parser::ObjectType::kNormal;
+ // Since the /Index does not follow the spec, this is one of the 2 possible
+ // values that a parser can come up with.
+ expected_result[1].pos = 15;
+ EXPECT_THAT(objects_info, ElementsAre(Pair(2, expected_result[0]),
+ Pair(3, expected_result[1])));
+}
+
+TEST_F(ParserXRefTest, XrefIndexWithOutOfOrderObjects) {
+ // The /Index specifies objects (3, 4), (2), which is not in ascending order.
+ const unsigned char kData[] =
+ "%PDF1-7\n%\xa0\xf2\xa4\xf4\n"
+ "7 0 obj <<\n"
+ " /Filter /ASCIIHexDecode\n"
+ " /Root 1 0 R\n"
+ " /Size 5\n"
+ " /Index [3 2 2 1]\n"
+ " /W [1 1 1]\n"
+ ">>\n"
+ "stream\n"
+ "01 00 00\n"
+ "01 0F 00\n"
+ "01 12 00\n"
+ "endstream\n"
+ "endobj\n"
+ "startxref\n"
+ "14\n"
+ "%%EOF\n";
+
+ ASSERT_TRUE(parser().InitTestFromBuffer(kData));
+ EXPECT_EQ(CPDF_Parser::SUCCESS, parser().StartParseInternal());
+ EXPECT_FALSE(parser().xref_table_rebuilt());
+ ASSERT_TRUE(parser().GetCrossRefTable());
+ const auto& objects_info = parser().GetCrossRefTable()->objects_info();
+
+ // Although the /Index does not follow the spec, the parser tolerates it.
+ CPDF_Parser::ObjectInfo expected_result[3];
+ expected_result[0].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[0].pos = 18;
+ expected_result[1].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[1].pos = 0;
+ expected_result[2].type = CPDF_Parser::ObjectType::kNormal;
+ expected_result[2].pos = 15;
+ EXPECT_THAT(objects_info, ElementsAre(Pair(2, expected_result[0]),
+ Pair(3, expected_result[1]),
+ Pair(4, expected_result[2])));
+}