From 898690313426bf1604e0bb6def684db84a782494 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Mon, 6 Nov 2017 20:01:13 +0000 Subject: Add a CPDF_PSEngine test. Change-Id: Ia267f40dc4ebe9e1d28b6a333eddcff749414ffa Reviewed-on: https://pdfium-review.googlesource.com/17870 Reviewed-by: dsinclair Commit-Queue: Lei Zhang --- BUILD.gn | 1 + core/fpdfapi/page/cpdf_psengine.cpp | 127 ++++++++++++++------------- core/fpdfapi/page/cpdf_psengine.h | 30 ++++++- core/fpdfapi/page/cpdf_psengine_unittest.cpp | 56 ++++++++++++ 4 files changed, 150 insertions(+), 64 deletions(-) create mode 100644 core/fpdfapi/page/cpdf_psengine_unittest.cpp diff --git a/BUILD.gn b/BUILD.gn index c77c23672f..39312a0106 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1938,6 +1938,7 @@ test("pdfium_unittests") { "core/fpdfapi/font/cpdf_cmapparser_unittest.cpp", "core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp", "core/fpdfapi/page/cpdf_devicecs_unittest.cpp", + "core/fpdfapi/page/cpdf_psengine_unittest.cpp", "core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp", "core/fpdfapi/page/cpdf_streamparser_unittest.cpp", "core/fpdfapi/parser/cpdf_array_unittest.cpp", diff --git a/core/fpdfapi/page/cpdf_psengine.cpp b/core/fpdfapi/page/cpdf_psengine.cpp index d879ead9c1..9dfa9989f0 100644 --- a/core/fpdfapi/page/cpdf_psengine.cpp +++ b/core/fpdfapi/page/cpdf_psengine.cpp @@ -46,39 +46,32 @@ const PDF_PSOpName kPsOpNames[] = { } // namespace -class CPDF_PSOP { - public: - explicit CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) { - ASSERT(m_op != PSOP_CONST); - ASSERT(m_op != PSOP_PROC); - } - explicit CPDF_PSOP(float value) : m_op(PSOP_CONST), m_value(value) {} - CPDF_PSOP() - : m_op(PSOP_PROC), - m_value(0), - m_proc(pdfium::MakeUnique()) {} - - float GetFloatValue() const { - if (m_op == PSOP_CONST) - return m_value; - - NOTREACHED(); - return 0; - } - CPDF_PSProc* GetProc() const { - if (m_op == PSOP_PROC) - return m_proc.get(); - NOTREACHED(); - return nullptr; - } +CPDF_PSOP::CPDF_PSOP() + : m_op(PSOP_PROC), m_value(0), m_proc(pdfium::MakeUnique()) {} - PDF_PSOP GetOp() const { return m_op; } +CPDF_PSOP::CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) { + ASSERT(m_op != PSOP_CONST); + ASSERT(m_op != PSOP_PROC); +} - private: - const PDF_PSOP m_op; - const float m_value; - std::unique_ptr m_proc; -}; +CPDF_PSOP::CPDF_PSOP(float value) : m_op(PSOP_CONST), m_value(value) {} + +CPDF_PSOP::~CPDF_PSOP() {} + +float CPDF_PSOP::GetFloatValue() const { + if (m_op == PSOP_CONST) + return m_value; + + NOTREACHED(); + return 0; +} + +CPDF_PSProc* CPDF_PSOP::GetProc() const { + if (m_op == PSOP_PROC) + return m_proc.get(); + NOTREACHED(); + return nullptr; +} bool CPDF_PSEngine::Execute() { return m_MainProc.Execute(this); @@ -87,6 +80,29 @@ bool CPDF_PSEngine::Execute() { CPDF_PSProc::CPDF_PSProc() {} CPDF_PSProc::~CPDF_PSProc() {} +bool CPDF_PSProc::Parse(CPDF_SimpleParser* parser, int depth) { + if (depth > kMaxDepth) + return false; + + while (1) { + ByteStringView word = parser->GetWord(); + if (word.IsEmpty()) + return false; + + if (word == "}") + return true; + + if (word == "{") { + m_Operators.push_back(pdfium::MakeUnique()); + if (!m_Operators.back()->GetProc()->Parse(parser, depth + 1)) + return false; + continue; + } + + AddOperator(word); + } +} + bool CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) { for (size_t i = 0; i < m_Operators.size(); ++i) { const PDF_PSOP op = m_Operators[i]->GetOp(); @@ -118,6 +134,23 @@ bool CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) { return true; } +void CPDF_PSProc::AddOperatorForTesting(const ByteStringView& word) { + AddOperator(word); +} + +void CPDF_PSProc::AddOperator(const ByteStringView& word) { + std::unique_ptr op; + for (const PDF_PSOpName& op_name : kPsOpNames) { + if (word == ByteStringView(op_name.name)) { + op = pdfium::MakeUnique(op_name.op); + break; + } + } + if (!op) + op = pdfium::MakeUnique(FX_atof(word)); + m_Operators.push_back(std::move(op)); +} + CPDF_PSEngine::CPDF_PSEngine() : m_StackCount(0) {} CPDF_PSEngine::~CPDF_PSEngine() {} @@ -141,38 +174,6 @@ bool CPDF_PSEngine::Parse(const char* str, int size) { return word == "{" ? m_MainProc.Parse(&parser, 0) : false; } -bool CPDF_PSProc::Parse(CPDF_SimpleParser* parser, int depth) { - if (depth > kMaxDepth) - return false; - - while (1) { - ByteStringView word = parser->GetWord(); - if (word.IsEmpty()) - return false; - - if (word == "}") - return true; - - if (word == "{") { - m_Operators.push_back(pdfium::MakeUnique()); - if (!m_Operators.back()->GetProc()->Parse(parser, depth + 1)) - return false; - continue; - } - - std::unique_ptr op; - for (const PDF_PSOpName& op_name : kPsOpNames) { - if (word == ByteStringView(op_name.name)) { - op = pdfium::MakeUnique(op_name.op); - break; - } - } - if (!op) - op = pdfium::MakeUnique(FX_atof(word)); - m_Operators.push_back(std::move(op)); - } -} - bool CPDF_PSEngine::DoOperator(PDF_PSOP op) { int i1; int i2; diff --git a/core/fpdfapi/page/cpdf_psengine.h b/core/fpdfapi/page/cpdf_psengine.h index 0d5eadd78e..63d91d0757 100644 --- a/core/fpdfapi/page/cpdf_psengine.h +++ b/core/fpdfapi/page/cpdf_psengine.h @@ -10,10 +10,11 @@ #include #include +#include "core/fxcrt/fx_string.h" #include "core/fxcrt/fx_system.h" class CPDF_PSEngine; -class CPDF_PSOP; +class CPDF_PSProc; class CPDF_SimpleParser; enum PDF_PSOP : uint8_t { @@ -63,6 +64,23 @@ enum PDF_PSOP : uint8_t { PSOP_CONST }; +class CPDF_PSOP { + public: + CPDF_PSOP(); + explicit CPDF_PSOP(PDF_PSOP op); + explicit CPDF_PSOP(float value); + ~CPDF_PSOP(); + + float GetFloatValue() const; + CPDF_PSProc* GetProc() const; + PDF_PSOP GetOp() const { return m_op; } + + private: + const PDF_PSOP m_op; + const float m_value; + std::unique_ptr m_proc; +}; + class CPDF_PSProc { public: CPDF_PSProc(); @@ -71,8 +89,18 @@ class CPDF_PSProc { bool Parse(CPDF_SimpleParser* parser, int depth); bool Execute(CPDF_PSEngine* pEngine); + // These methods are exposed for testing. + void AddOperatorForTesting(const ByteStringView& word); + size_t num_operators() const { return m_Operators.size(); } + const std::unique_ptr& last_operator() { + return m_Operators.back(); + } + private: static const int kMaxDepth = 128; + + void AddOperator(const ByteStringView& word); + std::vector> m_Operators; }; diff --git a/core/fpdfapi/page/cpdf_psengine_unittest.cpp b/core/fpdfapi/page/cpdf_psengine_unittest.cpp new file mode 100644 index 0000000000..f966c3aced --- /dev/null +++ b/core/fpdfapi/page/cpdf_psengine_unittest.cpp @@ -0,0 +1,56 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/cpdf_psengine.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CPDF_PSProc, AddOperator) { + static const struct { + const char* name; + PDF_PSOP op; + } kTestData[] = { + {"add", PSOP_ADD}, {"sub", PSOP_SUB}, + {"mul", PSOP_MUL}, {"div", PSOP_DIV}, + {"idiv", PSOP_IDIV}, {"mod", PSOP_MOD}, + {"neg", PSOP_NEG}, {"abs", PSOP_ABS}, + {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR}, + {"round", PSOP_ROUND}, {"truncate", PSOP_TRUNCATE}, + {"sqrt", PSOP_SQRT}, {"sin", PSOP_SIN}, + {"cos", PSOP_COS}, {"atan", PSOP_ATAN}, + {"exp", PSOP_EXP}, {"ln", PSOP_LN}, + {"log", PSOP_LOG}, {"cvi", PSOP_CVI}, + {"cvr", PSOP_CVR}, {"eq", PSOP_EQ}, + {"ne", PSOP_NE}, {"gt", PSOP_GT}, + {"ge", PSOP_GE}, {"lt", PSOP_LT}, + {"le", PSOP_LE}, {"and", PSOP_AND}, + {"or", PSOP_OR}, {"xor", PSOP_XOR}, + {"not", PSOP_NOT}, {"bitshift", PSOP_BITSHIFT}, + {"true", PSOP_TRUE}, {"false", PSOP_FALSE}, + {"if", PSOP_IF}, {"ifelse", PSOP_IFELSE}, + {"pop", PSOP_POP}, {"exch", PSOP_EXCH}, + {"dup", PSOP_DUP}, {"copy", PSOP_COPY}, + {"index", PSOP_INDEX}, {"roll", PSOP_ROLL}, + {"55", PSOP_CONST}, {"123.4", PSOP_CONST}, + {"-5", PSOP_CONST}, {"invalid", PSOP_CONST}, + }; + + CPDF_PSProc proc; + EXPECT_EQ(0U, proc.num_operators()); + for (size_t i = 0; i < FX_ArraySize(kTestData); ++i) { + ByteStringView word(kTestData[i].name); + proc.AddOperatorForTesting(word); + ASSERT_EQ(i + 1, proc.num_operators()); + const std::unique_ptr& new_psop = proc.last_operator(); + ASSERT_TRUE(new_psop); + PDF_PSOP new_op = new_psop->GetOp(); + EXPECT_EQ(kTestData[i].op, new_op); + if (new_op == PSOP_CONST) { + float fv = new_psop->GetFloatValue(); + if (word == "invalid") + EXPECT_FLOAT_EQ(0, fv); + else + EXPECT_EQ(word, ByteString::FormatFloat(fv)); + } + } +} -- cgit v1.2.3