From a5d7ad3aa8feb08a14b5cca173d673054c1ade23 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Thu, 13 Sep 2018 17:41:52 +0000 Subject: Introduce FX_Number class as a replacement for FX_atonum(). The issue with FX_atonum() is that it doesn't return any information about whether it range-checked its integer values as a signed or unsigned type, even though it knows this as part of its processing. Rather than adding another out parameter to that function, create a class to hold all this information together. This is the first place things went astray while diagnosing bug 882959, in that a large positive value was cast to float as a negative value. Unfortunately, this doesn't affect the related bug, but is a step in the right direction. Change-Id: I0977ec8fccf85e2632a962507bdd30a1cbe6d33c Reviewed-on: https://pdfium-review.googlesource.com/42353 Reviewed-by: Lei Zhang Commit-Queue: Tom Sepez --- BUILD.gn | 3 + core/fpdfapi/page/cpdf_streamcontentparser.cpp | 31 +++-- core/fpdfapi/page/cpdf_streamcontentparser.h | 9 +- core/fpdfapi/parser/cpdf_number.cpp | 24 ++-- core/fpdfapi/parser/cpdf_number.h | 11 +- core/fxcrt/fx_number.cpp | 104 ++++++++++++++++ core/fxcrt/fx_number.h | 39 ++++++ core/fxcrt/fx_number_unittest.cpp | 165 +++++++++++++++++++++++++ core/fxcrt/fx_string.cpp | 63 ---------- core/fxcrt/fx_string.h | 3 +- core/fxcrt/fx_string_unittest.cpp | 47 ------- 11 files changed, 345 insertions(+), 154 deletions(-) create mode 100644 core/fxcrt/fx_number.cpp create mode 100644 core/fxcrt/fx_number.h create mode 100644 core/fxcrt/fx_number_unittest.cpp diff --git a/BUILD.gn b/BUILD.gn index 1d4573a8f2..6df4732d71 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -885,6 +885,8 @@ jumbo_static_library("fxcrt") { "core/fxcrt/fx_extension.h", "core/fxcrt/fx_memory.cpp", "core/fxcrt/fx_memory.h", + "core/fxcrt/fx_number.cpp", + "core/fxcrt/fx_number.h", "core/fxcrt/fx_random.cpp", "core/fxcrt/fx_random.h", "core/fxcrt/fx_safe_types.h", @@ -2912,6 +2914,7 @@ test("pdfium_unittests") { "core/fxcrt/fx_coordinates_unittest.cpp", "core/fxcrt/fx_extension_unittest.cpp", "core/fxcrt/fx_memory_unittest.cpp", + "core/fxcrt/fx_number_unittest.cpp", "core/fxcrt/fx_random_unittest.cpp", "core/fxcrt/fx_string_unittest.cpp", "core/fxcrt/fx_system_unittest.cpp", diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp index 2244232ecb..20892cc264 100644 --- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp +++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp @@ -338,7 +338,7 @@ void CPDF_StreamContentParser::AddNameParam(const ByteStringView& bsName) { void CPDF_StreamContentParser::AddNumberParam(const ByteStringView& str) { ContentParam& param = m_ParamBuf[GetNextParamPos()]; param.m_Type = ContentParam::NUMBER; - param.m_Number.m_bInteger = FX_atonum(str, ¶m.m_Number.m_Integer); + param.m_Number = FX_Number(str); } void CPDF_StreamContentParser::AddObjectParam( @@ -373,9 +373,9 @@ CPDF_Object* CPDF_StreamContentParser::GetObject(uint32_t index) { if (param.m_Type == ContentParam::NUMBER) { param.m_Type = ContentParam::OBJECT; param.m_pObject = - param.m_Number.m_bInteger - ? pdfium::MakeUnique(param.m_Number.m_Integer) - : pdfium::MakeUnique(param.m_Number.m_Float); + param.m_Number.IsInteger() + ? pdfium::MakeUnique(param.m_Number.GetSigned()) + : pdfium::MakeUnique(param.m_Number.GetFloat()); return param.m_pObject.get(); } if (param.m_Type == ContentParam::NAME) { @@ -411,21 +411,20 @@ ByteString CPDF_StreamContentParser::GetString(uint32_t index) const { } float CPDF_StreamContentParser::GetNumber(uint32_t index) const { - if (index >= m_ParamCount) { + if (index >= m_ParamCount) return 0; - } + int real_index = m_ParamStartPos + m_ParamCount - index - 1; - if (real_index >= kParamBufSize) { + if (real_index >= kParamBufSize) real_index -= kParamBufSize; - } + const ContentParam& param = m_ParamBuf[real_index]; - if (param.m_Type == ContentParam::NUMBER) { - return param.m_Number.m_bInteger - ? static_cast(param.m_Number.m_Integer) - : param.m_Number.m_Float; - } + if (param.m_Type == ContentParam::NUMBER) + return param.m_Number.GetFloat(); + if (param.m_Type == 0 && param.m_pObject) return param.m_pObject->GetNumber(); + return 0; } @@ -1632,10 +1631,8 @@ void CPDF_StreamContentParser::ParsePathObject() { if (nParams == 6) break; - int value; - bool bInteger = FX_atonum(m_pSyntax->GetWord(), &value); - params[nParams++] = bInteger ? static_cast(value) - : *reinterpret_cast(&value); + FX_Number number(m_pSyntax->GetWord()); + params[nParams++] = number.GetFloat(); break; } default: diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h index a129894dba..6417043305 100644 --- a/core/fpdfapi/page/cpdf_streamcontentparser.h +++ b/core/fpdfapi/page/cpdf_streamcontentparser.h @@ -15,6 +15,7 @@ #include "core/fpdfapi/page/cpdf_contentmark.h" #include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/fx_number.h" #include "core/fxcrt/fx_string.h" #include "core/fxge/cfx_pathdata.h" @@ -71,13 +72,7 @@ class CPDF_StreamContentParser { Type m_Type; std::unique_ptr m_pObject; - struct { - bool m_bInteger; - union { - int m_Integer; - float m_Float; - }; - } m_Number; + FX_Number m_Number; struct { int m_Len; char m_Buffer[32]; diff --git a/core/fpdfapi/parser/cpdf_number.cpp b/core/fpdfapi/parser/cpdf_number.cpp index b75ce0766a..23c2609e25 100644 --- a/core/fpdfapi/parser/cpdf_number.cpp +++ b/core/fpdfapi/parser/cpdf_number.cpp @@ -8,14 +8,13 @@ #include "core/fxcrt/fx_stream.h" #include "third_party/base/ptr_util.h" -CPDF_Number::CPDF_Number() : m_bInteger(true), m_Integer(0) {} +CPDF_Number::CPDF_Number() {} -CPDF_Number::CPDF_Number(int value) : m_bInteger(true), m_Integer(value) {} +CPDF_Number::CPDF_Number(int value) : m_Number(value) {} -CPDF_Number::CPDF_Number(float value) : m_bInteger(false), m_Float(value) {} +CPDF_Number::CPDF_Number(float value) : m_Number(value) {} -CPDF_Number::CPDF_Number(const ByteStringView& str) - : m_bInteger(FX_atonum(str, &m_Integer)) {} +CPDF_Number::CPDF_Number(const ByteStringView& str) : m_Number(str) {} CPDF_Number::~CPDF_Number() {} @@ -24,16 +23,17 @@ CPDF_Object::Type CPDF_Number::GetType() const { } std::unique_ptr CPDF_Number::Clone() const { - return m_bInteger ? pdfium::MakeUnique(m_Integer) - : pdfium::MakeUnique(m_Float); + return m_Number.IsInteger() + ? pdfium::MakeUnique(m_Number.GetSigned()) + : pdfium::MakeUnique(m_Number.GetFloat()); } float CPDF_Number::GetNumber() const { - return m_bInteger ? static_cast(m_Integer) : m_Float; + return m_Number.GetFloat(); } int CPDF_Number::GetInteger() const { - return m_bInteger ? m_Integer : static_cast(m_Float); + return m_Number.GetSigned(); } bool CPDF_Number::IsNumber() const { @@ -49,12 +49,12 @@ const CPDF_Number* CPDF_Number::AsNumber() const { } void CPDF_Number::SetString(const ByteString& str) { - m_bInteger = FX_atonum(str.AsStringView(), &m_Integer); + m_Number = FX_Number(str.AsStringView()); } ByteString CPDF_Number::GetString() const { - return m_bInteger ? ByteString::FormatInteger(m_Integer) - : ByteString::FormatFloat(m_Float); + return m_Number.IsInteger() ? ByteString::FormatInteger(m_Number.GetSigned()) + : ByteString::FormatFloat(m_Number.GetFloat()); } bool CPDF_Number::WriteTo(IFX_ArchiveStream* archive, diff --git a/core/fpdfapi/parser/cpdf_number.h b/core/fpdfapi/parser/cpdf_number.h index b5faf82bb2..724ae9f1f1 100644 --- a/core/fpdfapi/parser/cpdf_number.h +++ b/core/fpdfapi/parser/cpdf_number.h @@ -10,6 +10,7 @@ #include #include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/fx_number.h" #include "core/fxcrt/fx_string.h" #include "core/fxcrt/fx_system.h" @@ -34,14 +35,10 @@ class CPDF_Number final : public CPDF_Object { bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; - bool IsInteger() const { return m_bInteger; } + bool IsInteger() const { return m_Number.IsInteger(); } - protected: - bool m_bInteger; - union { - int m_Integer; - float m_Float; - }; + private: + FX_Number m_Number; }; inline CPDF_Number* ToNumber(CPDF_Object* obj) { diff --git a/core/fxcrt/fx_number.cpp b/core/fxcrt/fx_number.cpp new file mode 100644 index 0000000000..68d5bd9b32 --- /dev/null +++ b/core/fxcrt/fx_number.cpp @@ -0,0 +1,104 @@ +// Copyright 2018 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. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcrt/fx_number.h" + +#include + +#include "core/fxcrt/fx_extension.h" +#include "core/fxcrt/fx_string.h" + +FX_Number::FX_Number() + : m_bInteger(true), m_bSigned(false), m_UnsignedValue(0) {} + +FX_Number::FX_Number(uint32_t value) + : m_bInteger(true), m_bSigned(false), m_UnsignedValue(value) {} + +FX_Number::FX_Number(int32_t value) + : m_bInteger(true), m_bSigned(true), m_SignedValue(value) {} + +FX_Number::FX_Number(float value) + : m_bInteger(false), m_bSigned(true), m_FloatValue(value) {} + +FX_Number::FX_Number(const ByteStringView& strc) + : m_bInteger(true), m_bSigned(false), m_UnsignedValue(0) { + if (strc.IsEmpty()) + return; + + if (strc.Contains('.')) { + m_bInteger = false; + m_bSigned = true; + m_FloatValue = FX_atof(strc); + return; + } + + // Note, numbers in PDF are typically of the form 123, -123, etc. But, + // for things like the Permissions on the encryption hash the number is + // actually an unsigned value. We use a uint32_t so we can deal with the + // unsigned and then check for overflow if the user actually signed the value. + // The Permissions flag is listed in Table 3.20 PDF 1.7 spec. + pdfium::base::CheckedNumeric unsigned_val = 0; + bool bNegative = false; + size_t cc = 0; + if (strc[0] == '+') { + cc++; + m_bSigned = true; + } else if (strc[0] == '-') { + bNegative = true; + m_bSigned = true; + cc++; + } + + while (cc < strc.GetLength() && std::isdigit(strc[cc])) { + unsigned_val = unsigned_val * 10 + FXSYS_DecimalCharToInt(strc.CharAt(cc)); + if (!unsigned_val.IsValid()) + break; + cc++; + } + + uint32_t uValue = unsigned_val.ValueOrDefault(0); + if (!m_bSigned) { + m_UnsignedValue = uValue; + return; + } + + // We have a sign, so if the value was greater then the signed integer + // limits, then we've overflowed and must reset to the default value. + constexpr uint32_t uLimit = + static_cast(std::numeric_limits::max()); + + if (uValue > (bNegative ? uLimit + 1 : uLimit)) + uValue = 0; + + // Switch back to the int space so we can flip to a negative if we need. + int32_t value = static_cast(uValue); + if (bNegative) { + // |value| is usually positive, except in the corner case of "-2147483648", + // where |uValue| is 2147483648. When it gets casted to an int, |value| + // becomes -2147483648. For this case, avoid undefined behavior, because + // an int32_t cannot represent 2147483648. + static constexpr int kMinInt = std::numeric_limits::min(); + m_SignedValue = LIKELY(value != kMinInt) ? -value : kMinInt; + } else { + m_SignedValue = value; + } +} + +uint32_t FX_Number::GetUnsigned() const { + return m_bInteger ? m_UnsignedValue : static_cast(m_FloatValue); +} + +int32_t FX_Number::GetSigned() const { + return m_bInteger ? m_SignedValue : static_cast(m_FloatValue); +} + +float FX_Number::GetFloat() const { + if (!m_bInteger) + return m_FloatValue; + + return m_bSigned ? static_cast(m_SignedValue) + : static_cast(m_UnsignedValue); +} diff --git a/core/fxcrt/fx_number.h b/core/fxcrt/fx_number.h new file mode 100644 index 0000000000..4c789b4130 --- /dev/null +++ b/core/fxcrt/fx_number.h @@ -0,0 +1,39 @@ +// Copyright 2018 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. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCRT_FX_NUMBER_H_ +#define CORE_FXCRT_FX_NUMBER_H_ + +#include + +#include "core/fxcrt/bytestring.h" + +class FX_Number { + public: + FX_Number(); + explicit FX_Number(uint32_t value); + explicit FX_Number(int32_t value); + explicit FX_Number(float value); + explicit FX_Number(const ByteStringView& str); + + bool IsInteger() const { return m_bInteger; } + bool IsSigned() const { return m_bSigned; } + + uint32_t GetUnsigned() const; // Underflow possible. + int32_t GetSigned() const; // Underflow/Overflow possible. + float GetFloat() const; + + private: + bool m_bInteger; // One of the two integers vs. float type. + bool m_bSigned; // Only valid if |m_bInteger|. + union { + uint32_t m_UnsignedValue; + int32_t m_SignedValue; + float m_FloatValue; + }; +}; + +#endif // CORE_FXCRT_FX_NUMBER_H_ diff --git a/core/fxcrt/fx_number_unittest.cpp b/core/fxcrt/fx_number_unittest.cpp new file mode 100644 index 0000000000..83702dadcf --- /dev/null +++ b/core/fxcrt/fx_number_unittest.cpp @@ -0,0 +1,165 @@ +// Copyright 2018 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 + +#include "core/fxcrt/fx_number.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(fxnumber, Default) { + FX_Number number; + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(0u, number.GetUnsigned()); + EXPECT_EQ(0, number.GetSigned()); + EXPECT_FLOAT_EQ(0.0f, number.GetFloat()); +} + +TEST(fxnumber, FromUnsigned) { + FX_Number number(42u); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(42u, number.GetUnsigned()); + EXPECT_EQ(42, number.GetSigned()); + EXPECT_FLOAT_EQ(42.0f, number.GetFloat()); + + // Show that assignment works. + FX_Number number2 = number; + EXPECT_TRUE(number2.IsInteger()); + EXPECT_FALSE(number2.IsSigned()); + EXPECT_EQ(42u, number2.GetUnsigned()); + EXPECT_EQ(42, number2.GetSigned()); + EXPECT_FLOAT_EQ(42.0F, number2.GetFloat()); +} + +TEST(fxnumber, FromSigned) { + FX_Number number(-128); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(4294967168u, number.GetUnsigned()); + EXPECT_EQ(-128, number.GetSigned()); + EXPECT_FLOAT_EQ(-128.0f, number.GetFloat()); + + // Show that assignment works. + FX_Number number2 = number; + EXPECT_TRUE(number2.IsInteger()); + EXPECT_TRUE(number2.IsSigned()); + EXPECT_EQ(4294967168u, number2.GetUnsigned()); + EXPECT_EQ(-128, number2.GetSigned()); + EXPECT_FLOAT_EQ(-128.0f, number2.GetFloat()); +} + +TEST(fxnumber, FromFloat) { + FX_Number number(-100.001f); + EXPECT_FALSE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(4294967196u, number.GetUnsigned()); + EXPECT_EQ(-100, number.GetSigned()); + EXPECT_FLOAT_EQ(-100.001f, number.GetFloat()); + + // Show that assignment works. + FX_Number number2 = number; + EXPECT_FALSE(number2.IsInteger()); + EXPECT_TRUE(number2.IsSigned()); + EXPECT_EQ(4294967196u, number2.GetUnsigned()); + EXPECT_EQ(-100, number2.GetSigned()); + EXPECT_FLOAT_EQ(-100.001f, number2.GetFloat()); +} + +TEST(fxnumber, FromStringUnsigned) { + { + FX_Number number(""); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(0u, number.GetUnsigned()); + } + { + FX_Number number("0"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(0u, number.GetUnsigned()); + } + { + FX_Number number("10"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(10u, number.GetUnsigned()); + } + { + FX_Number number("4294967295"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(std::numeric_limits::max(), number.GetUnsigned()); + } + { + // Value overflows. + FX_Number number("4223423494965252"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_FALSE(number.IsSigned()); + EXPECT_EQ(0u, number.GetUnsigned()); + } + { + // No explicit sign will allow the number to go negative if we retrieve + // it as a signed value. This is needed for things like the encryption + // Permissions flag (Table 3.20 PDF 1.7 spec) + FX_Number number("4294965252"); + EXPECT_EQ(-2044, number.GetSigned()); + } +} + +TEST(fxnumber, FromStringSigned) { + { + FX_Number number("-0"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(0, number.GetSigned()); + } + { + FX_Number number("+0"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(0, number.GetSigned()); + } + { + FX_Number number("-10"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(-10, number.GetSigned()); + } + { + FX_Number number("+10"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(10, number.GetSigned()); + } + { + FX_Number number("-2147483648"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(std::numeric_limits::min(), number.GetSigned()); + } + { + FX_Number number("+2147483647"); + EXPECT_TRUE(number.IsInteger()); + EXPECT_TRUE(number.IsSigned()); + EXPECT_EQ(std::numeric_limits::max(), number.GetSigned()); + } + { + // Value underflows. + FX_Number number("-2147483649"); + EXPECT_EQ(0u, number.GetUnsigned()); + EXPECT_EQ(0, number.GetSigned()); + } + { + // Value overflows. + FX_Number number("+2147483648"); + EXPECT_EQ(0u, number.GetUnsigned()); + EXPECT_EQ(0, number.GetSigned()); + } +} + +TEST(fxnumber, FromStringFloat) { + FX_Number number("3.24"); + EXPECT_FLOAT_EQ(3.24f, number.GetFloat()); +} diff --git a/core/fxcrt/fx_string.cpp b/core/fxcrt/fx_string.cpp index c9993f9ab8..31eb8e917d 100644 --- a/core/fxcrt/fx_string.cpp +++ b/core/fxcrt/fx_string.cpp @@ -47,69 +47,6 @@ float FractionalScale(size_t scale_factor, int value) { } // namespace -bool FX_atonum(const ByteStringView& strc, void* pData) { - if (strc.Contains('.')) { - float* pFloat = static_cast(pData); - *pFloat = FX_atof(strc); - return false; - } - - // Note, numbers in PDF are typically of the form 123, -123, etc. But, - // for things like the Permissions on the encryption hash the number is - // actually an unsigned value. We use a uint32_t so we can deal with the - // unsigned and then check for overflow if the user actually signed the value. - // The Permissions flag is listed in Table 3.20 PDF 1.7 spec. - pdfium::base::CheckedNumeric integer = 0; - bool bNegative = false; - bool bSigned = false; - size_t cc = 0; - if (strc[0] == '+') { - cc++; - bSigned = true; - } else if (strc[0] == '-') { - bNegative = true; - bSigned = true; - cc++; - } - - while (cc < strc.GetLength() && std::isdigit(strc[cc])) { - integer = integer * 10 + FXSYS_DecimalCharToInt(strc.CharAt(cc)); - if (!integer.IsValid()) - break; - cc++; - } - - // We have a sign, and the value was greater then a regular integer - // we've overflowed, reset to the default value. - if (bSigned) { - if (bNegative) { - if (integer.ValueOrDefault(0) > - static_cast(std::numeric_limits::max()) + 1) { - integer = 0; - } - } else if (integer.ValueOrDefault(0) > - static_cast(std::numeric_limits::max())) { - integer = 0; - } - } - - // Switch back to the int space so we can flip to a negative if we need. - uint32_t uValue = integer.ValueOrDefault(0); - int32_t value = static_cast(uValue); - if (bNegative) { - // |value| is usually positive, except in the corner case of "-2147483648", - // where |uValue| is 2147483648. When it gets casted to an int, |value| - // becomes -2147483648. For this case, avoid undefined behavior, because an - // integer cannot represent 2147483648. - static constexpr int kMinInt = std::numeric_limits::min(); - value = LIKELY(value != kMinInt) ? -value : kMinInt; - } - - int* pInt = static_cast(pData); - *pInt = value; - return true; -} - float FX_atof(const ByteStringView& strc) { if (strc.IsEmpty()) return 0.0; diff --git a/core/fxcrt/fx_string.h b/core/fxcrt/fx_string.h index 2cf823738a..670aa4d4b7 100644 --- a/core/fxcrt/fx_string.h +++ b/core/fxcrt/fx_string.h @@ -7,6 +7,8 @@ #ifndef CORE_FXCRT_FX_STRING_H_ #define CORE_FXCRT_FX_STRING_H_ +#include + #include "core/fxcrt/bytestring.h" #include "core/fxcrt/widestring.h" @@ -19,7 +21,6 @@ WideString FX_UTF8Decode(const ByteStringView& bsStr); float FX_atof(const ByteStringView& str); float FX_atof(const WideStringView& wsStr); -bool FX_atonum(const ByteStringView& str, void* pData); size_t FX_ftoa(float f, char* buf); #endif // CORE_FXCRT_FX_STRING_H_ diff --git a/core/fxcrt/fx_string_unittest.cpp b/core/fxcrt/fx_string_unittest.cpp index 60e7f07523..3059de3e5c 100644 --- a/core/fxcrt/fx_string_unittest.cpp +++ b/core/fxcrt/fx_string_unittest.cpp @@ -2,56 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include - #include "core/fxcrt/fx_string.h" #include "testing/gtest/include/gtest/gtest.h" -TEST(fxstring, FX_atonum) { - int i; - EXPECT_TRUE(FX_atonum("10", &i)); - EXPECT_EQ(10, i); - - EXPECT_TRUE(FX_atonum("-10", &i)); - EXPECT_EQ(-10, i); - - EXPECT_TRUE(FX_atonum("+10", &i)); - EXPECT_EQ(10, i); - - EXPECT_TRUE(FX_atonum("-2147483648", &i)); - EXPECT_EQ(std::numeric_limits::min(), i); - - EXPECT_TRUE(FX_atonum("2147483647", &i)); - EXPECT_EQ(2147483647, i); - - // Value overflows. - EXPECT_TRUE(FX_atonum("-2147483649", &i)); - EXPECT_EQ(0, i); - - // Value overflows. - EXPECT_TRUE(FX_atonum("+2147483648", &i)); - EXPECT_EQ(0, i); - - // Value overflows. - EXPECT_TRUE(FX_atonum("4223423494965252", &i)); - EXPECT_EQ(0, i); - - // No explicit sign will allow the number to go negative. This is for things - // like the encryption Permissions flag (Table 3.20 PDF 1.7 spec) - EXPECT_TRUE(FX_atonum("4294965252", &i)); - EXPECT_EQ(-2044, i); - - EXPECT_TRUE(FX_atonum("-4294965252", &i)); - EXPECT_EQ(0, i); - - EXPECT_TRUE(FX_atonum("+4294965252", &i)); - EXPECT_EQ(0, i); - - float f; - EXPECT_FALSE(FX_atonum("3.24", &f)); - EXPECT_FLOAT_EQ(3.24f, f); -} - TEST(fxstring, FX_UTF8Encode) { EXPECT_EQ("", FX_UTF8Encode(WideStringView())); EXPECT_EQ( -- cgit v1.2.3