aboutsummaryrefslogtreecommitdiff
path: root/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp')
-rw-r--r--core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp274
1 files changed, 235 insertions, 39 deletions
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index 311226f85..2c2074b66 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -1,17 +1,22 @@
-// Copyright 2015 PDFium Authors. All rights reserved.
+// Copyright 2015 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include <iterator>
+
#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fxcrt/fx_memory_wrappers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/test_support.h"
-TEST(fpdf_parser_decode, ValidateDecoderPipeline) {
+TEST(ParserDecodeTest, ValidateDecoderPipeline) {
{
// Empty decoder list is always valid.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
@@ -20,99 +25,221 @@ TEST(fpdf_parser_decode, ValidateDecoderPipeline) {
{
// 1 decoder is almost always valid.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("FlateEncode");
+ decoders->AppendNew<CPDF_Name>("FlateEncode");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// 1 decoder is almost always valid, even with an unknown decoder.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("FooBar");
+ decoders->AppendNew<CPDF_Name>("FooBar");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Valid 2 decoder pipeline.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("AHx");
- decoders->AddNew<CPDF_Name>("LZWDecode");
+ decoders->AppendNew<CPDF_Name>("AHx");
+ decoders->AppendNew<CPDF_Name>("LZWDecode");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Valid 2 decoder pipeline.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("ASCII85Decode");
- decoders->AddNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Valid 5 decoder pipeline.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("ASCII85Decode");
- decoders->AddNew<CPDF_Name>("A85");
- decoders->AddNew<CPDF_Name>("RunLengthDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_Name>("RL");
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("A85");
+ decoders->AppendNew<CPDF_Name>("RunLengthDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("RL");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Valid 5 decoder pipeline, with an image decoder at the end.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("RunLengthDecode");
- decoders->AddNew<CPDF_Name>("ASCII85Decode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_Name>("LZW");
- decoders->AddNew<CPDF_Name>("DCTDecode");
+ decoders->AppendNew<CPDF_Name>("RunLengthDecode");
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("LZW");
+ decoders->AppendNew<CPDF_Name>("DCTDecode");
EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 1 decoder pipeline due to wrong type.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_String>("FlateEncode", false);
+ decoders->AppendNew<CPDF_String>("FlateEncode", false);
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 2 decoder pipeline, with 2 image decoders.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("DCTDecode");
- decoders->AddNew<CPDF_Name>("CCITTFaxDecode");
+ decoders->AppendNew<CPDF_Name>("DCTDecode");
+ decoders->AppendNew<CPDF_Name>("CCITTFaxDecode");
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 2 decoder pipeline, with 1 image decoder at the start.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("DCTDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("DCTDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 2 decoder pipeline due to wrong type.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_String>("AHx", false);
- decoders->AddNew<CPDF_Name>("LZWDecode");
+ decoders->AppendNew<CPDF_String>("AHx", false);
+ decoders->AppendNew<CPDF_Name>("LZWDecode");
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 5 decoder pipeline.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_Name>("DCTDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("DCTDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
{
// Invalid 5 decoder pipeline due to wrong type.
auto decoders = pdfium::MakeRetain<CPDF_Array>();
- decoders->AddNew<CPDF_Name>("ASCII85Decode");
- decoders->AddNew<CPDF_Name>("A85");
- decoders->AddNew<CPDF_Name>("RunLengthDecode");
- decoders->AddNew<CPDF_Name>("FlateDecode");
- decoders->AddNew<CPDF_String>("RL", false);
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("A85");
+ decoders->AppendNew<CPDF_Name>("RunLengthDecode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_String>("RL", false);
EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
}
}
-TEST(fpdf_parser_decode, A85Decode) {
+TEST(ParserDecodeTest, ValidateDecoderPipelineWithIndirectObjects) {
+ {
+ // Valid 2 decoder pipeline with indirect objects.
+ CPDF_IndirectObjectHolder objects_holder;
+ auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "FlateDecode");
+ uint32_t decoder_number =
+ objects_holder.AddIndirectObject(std::move(decoder));
+
+ auto decoders = pdfium::MakeRetain<CPDF_Array>();
+ decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+ decoders->AppendNew<CPDF_Name>("LZW");
+ EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
+ }
+ {
+ // Valid 5 decoder pipeline with indirect objects, with an image decoder at
+ // the end.
+ CPDF_IndirectObjectHolder objects_holder;
+ auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "LZW");
+ uint32_t decoder_number =
+ objects_holder.AddIndirectObject(std::move(decoder));
+
+ auto decoders = pdfium::MakeRetain<CPDF_Array>();
+ decoders->AppendNew<CPDF_Name>("RunLengthDecode");
+ decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+ decoders->AppendNew<CPDF_Name>("FlateDecode");
+ decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+ decoders->AppendNew<CPDF_Name>("DCTDecode");
+ EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
+ }
+ {
+ // Invalid 2 decoder pipeline due to wrong type indirect object.
+ CPDF_IndirectObjectHolder objects_holder;
+ auto decoder =
+ pdfium::MakeRetain<CPDF_String>(nullptr, "FlateDecode", false);
+ uint32_t decoder_number =
+ objects_holder.AddIndirectObject(std::move(decoder));
+
+ auto decoders = pdfium::MakeRetain<CPDF_Array>();
+ decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+ decoders->AppendNew<CPDF_Name>("LZW");
+ EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
+ }
+ {
+ // Invalid 2 decoder pipeline due to invalid indirect object.
+ CPDF_IndirectObjectHolder objects_holder;
+ auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "DCTDecode");
+ uint32_t decoder_number =
+ objects_holder.AddIndirectObject(std::move(decoder));
+
+ auto decoders = pdfium::MakeRetain<CPDF_Array>();
+ decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+ decoders->AppendNew<CPDF_Name>("LZW");
+ EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
+ }
+}
+
+// TODO(thestig): Test decoder params.
+TEST(ParserDecodeTest, GetDecoderArray) {
+ {
+ // Treat no filter as an empty filter array.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ ASSERT_TRUE(decoder_array.has_value());
+ EXPECT_TRUE(decoder_array.value().empty());
+ }
+ {
+ // Wrong filter type.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ dict->SetNewFor<CPDF_String>("Filter", "RL", false);
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ EXPECT_FALSE(decoder_array.has_value());
+ }
+ {
+ // Filter name.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ dict->SetNewFor<CPDF_Name>("Filter", "RL");
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ ASSERT_TRUE(decoder_array.has_value());
+ ASSERT_EQ(1u, decoder_array.value().size());
+ EXPECT_EQ("RL", decoder_array.value()[0].first);
+ }
+ {
+ // Empty filter array.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ dict->SetNewFor<CPDF_Array>("Filter");
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ ASSERT_TRUE(decoder_array.has_value());
+ EXPECT_TRUE(decoder_array.value().empty());
+ }
+ {
+ // Valid 1 element filter array.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ auto filter_array = dict->SetNewFor<CPDF_Array>("Filter");
+ filter_array->AppendNew<CPDF_Name>("FooBar");
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ ASSERT_TRUE(decoder_array.has_value());
+ ASSERT_EQ(1u, decoder_array.value().size());
+ EXPECT_EQ("FooBar", decoder_array.value()[0].first);
+ }
+ {
+ // Valid 2 element filter array.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ auto filter_array = dict->SetNewFor<CPDF_Array>("Filter");
+ filter_array->AppendNew<CPDF_Name>("AHx");
+ filter_array->AppendNew<CPDF_Name>("LZWDecode");
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ ASSERT_TRUE(decoder_array.has_value());
+ ASSERT_EQ(2u, decoder_array.value().size());
+ EXPECT_EQ("AHx", decoder_array.value()[0].first);
+ EXPECT_EQ("LZWDecode", decoder_array.value()[1].first);
+ }
+ {
+ // Invalid 2 element filter array.
+ auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ auto invalid_filter_array = dict->SetNewFor<CPDF_Array>("Filter");
+ invalid_filter_array->AppendNew<CPDF_Name>("DCTDecode");
+ invalid_filter_array->AppendNew<CPDF_Name>("CCITTFaxDecode");
+ absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict);
+ EXPECT_FALSE(decoder_array.has_value());
+ }
+}
+
+TEST(ParserDecodeTest, A85Decode) {
const pdfium::DecodeTestData kTestData[] = {
// Empty src string.
STR_IN_OUT_CASE("", "", 0),
@@ -147,7 +274,76 @@ TEST(fpdf_parser_decode, A85Decode) {
}
}
-TEST(fpdf_parser_decode, HexDecode) {
+// NOTE: python's zlib.compress() and zlib.decompress() may be useful for
+// external validation of the FlateDncode/FlateEecode test cases.
+TEST(FPDFParserDecodeEmbedderTest, FlateDecode) {
+ static const pdfium::DecodeTestData flate_decode_cases[] = {
+ STR_IN_OUT_CASE("", "", 0),
+ STR_IN_OUT_CASE("preposterous nonsense", "", 2),
+ STR_IN_OUT_CASE("\x78\x9c\x03\x00\x00\x00\x00\x01", "", 8),
+ STR_IN_OUT_CASE("\x78\x9c\x53\x00\x00\x00\x21\x00\x21", " ", 9),
+ STR_IN_OUT_CASE("\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97", "123", 11),
+ STR_IN_OUT_CASE("\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00", "\x00\xff",
+ 10),
+ STR_IN_OUT_CASE(
+ "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63"
+ "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a"
+ "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e"
+ "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57"
+ "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a"
+ "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42",
+ "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n"
+ "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n"
+ "0 0 693 917 re\nf\nQ\nQ\n",
+ 96),
+ };
+
+ for (size_t i = 0; i < std::size(flate_decode_cases); ++i) {
+ const pdfium::DecodeTestData& data = flate_decode_cases[i];
+ std::unique_ptr<uint8_t, FxFreeDeleter> buf;
+ uint32_t buf_size;
+ EXPECT_EQ(data.processed_size,
+ FlateDecode({data.input, data.input_size}, &buf, &buf_size))
+ << " for case " << i;
+ ASSERT_TRUE(buf);
+ EXPECT_EQ(data.expected_size, buf_size) << " for case " << i;
+ if (data.expected_size != buf_size)
+ continue;
+ EXPECT_EQ(0, memcmp(data.expected, buf.get(), data.expected_size))
+ << " for case " << i;
+ }
+}
+
+TEST(ParserDecodeTest, FlateEncode) {
+ static const pdfium::StrFuncTestData flate_encode_cases[] = {
+ STR_IN_OUT_CASE("", "\x78\x9c\x03\x00\x00\x00\x00\x01"),
+ STR_IN_OUT_CASE(" ", "\x78\x9c\x53\x00\x00\x00\x21\x00\x21"),
+ STR_IN_OUT_CASE("123", "\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97"),
+ STR_IN_OUT_CASE("\x00\xff", "\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00"),
+ STR_IN_OUT_CASE(
+ "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n"
+ "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n"
+ "0 0 693 917 re\nf\nQ\nQ\n",
+ "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63"
+ "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a"
+ "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e"
+ "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57"
+ "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a"
+ "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42"),
+ };
+
+ for (size_t i = 0; i < std::size(flate_encode_cases); ++i) {
+ const pdfium::StrFuncTestData& data = flate_encode_cases[i];
+ DataVector<uint8_t> result = FlateEncode({data.input, data.input_size});
+ EXPECT_EQ(data.expected_size, result.size()) << " for case " << i;
+ if (data.expected_size != result.size())
+ continue;
+ EXPECT_EQ(0, memcmp(data.expected, result.data(), data.expected_size))
+ << " for case " << i;
+ }
+}
+
+TEST(ParserDecodeTest, HexDecode) {
const pdfium::DecodeTestData kTestData[] = {
// Empty src string.
STR_IN_OUT_CASE("", "", 0),
@@ -182,7 +378,7 @@ TEST(fpdf_parser_decode, HexDecode) {
}
}
-TEST(fpdf_parser_decode, DecodeText) {
+TEST(ParserDecodeTest, DecodeText) {
const struct DecodeTestData {
const char* input;
size_t input_length;
@@ -231,7 +427,7 @@ TEST(fpdf_parser_decode, DecodeText) {
}
}
-TEST(fpdf_parser_decode, EncodeText) {
+TEST(ParserDecodeTest, EncodeText) {
const struct EncodeTestData {
const wchar_t* input;
const char* expected_output;