| // Copyright 2017 The PDFium Authors | |
| // 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_string.h" | |
| #include <stdint.h> | |
| #include <iterator> | |
| #include "build/build_config.h" | |
| #include "core/fxcrt/bytestring.h" | |
| #include "core/fxcrt/code_point_view.h" | |
| #include "core/fxcrt/fx_extension.h" | |
| #include "core/fxcrt/span_util.h" | |
| #include "core/fxcrt/string_view_template.h" | |
| #include "core/fxcrt/utf16.h" | |
| #include "core/fxcrt/widestring.h" | |
| #include "third_party/base/compiler_specific.h" | |
| #include "third_party/base/span.h" | |
| namespace { | |
| // Appends a Unicode code point to a `ByteString` using UTF-8. | |
| // | |
| // TODO(crbug.com/pdfium/2041): Migrate to `ByteString`. | |
| void AppendCodePointToByteString(char32_t code_point, ByteString& buffer) { | |
| if (code_point > pdfium::kMaximumSupplementaryCodePoint) { | |
| // Invalid code point above U+10FFFF. | |
| return; | |
| } | |
| if (code_point < 0x80) { | |
| // 7-bit code points are unchanged in UTF-8. | |
| buffer += code_point; | |
| return; | |
| } | |
| int byte_size; | |
| if (code_point < 0x800) { | |
| byte_size = 2; | |
| } else if (code_point < 0x10000) { | |
| byte_size = 3; | |
| } else { | |
| byte_size = 4; | |
| } | |
| static constexpr uint8_t kPrefix[] = {0xc0, 0xe0, 0xf0}; | |
| int order = 1 << ((byte_size - 1) * 6); | |
| buffer += kPrefix[byte_size - 2] | (code_point / order); | |
| for (int i = 0; i < byte_size - 1; i++) { | |
| code_point = code_point % order; | |
| order >>= 6; | |
| buffer += 0x80 | (code_point / order); | |
| } | |
| } | |
| // Appends a Unicode code point to a `WideString` using either UTF-16 or UTF-32, | |
| // depending on the platform's definition of `wchar_t`. | |
| // | |
| // TODO(crbug.com/pdfium/2031): Always use UTF-16. | |
| // TODO(crbug.com/pdfium/2041): Migrate to `WideString`. | |
| void AppendCodePointToWideString(char32_t code_point, WideString& buffer) { | |
| if (code_point > pdfium::kMaximumSupplementaryCodePoint) { | |
| // Invalid code point above U+10FFFF. | |
| return; | |
| } | |
| #if defined(WCHAR_T_IS_UTF16) | |
| if (code_point < pdfium::kMinimumSupplementaryCodePoint) { | |
| buffer += static_cast<wchar_t>(code_point); | |
| } else { | |
| // Encode as UTF-16 surrogate pair. | |
| pdfium::SurrogatePair surrogate_pair(code_point); | |
| buffer += surrogate_pair.high(); | |
| buffer += surrogate_pair.low(); | |
| } | |
| #else | |
| buffer += static_cast<wchar_t>(code_point); | |
| #endif // defined(WCHAR_T_IS_UTF16) | |
| } | |
| } // namespace | |
| ByteString FX_UTF8Encode(WideStringView wsStr) { | |
| ByteString buffer; | |
| for (char32_t code_point : pdfium::CodePointView(wsStr)) { | |
| AppendCodePointToByteString(code_point, buffer); | |
| } | |
| return buffer; | |
| } | |
| WideString FX_UTF8Decode(ByteStringView bsStr) { | |
| WideString buffer; | |
| int remaining = 0; | |
| char32_t code_point = 0; | |
| for (char byte : bsStr) { | |
| uint8_t code_unit = static_cast<uint8_t>(byte); | |
| if (code_unit < 0x80) { | |
| remaining = 0; | |
| AppendCodePointToWideString(code_unit, buffer); | |
| } else if (code_unit < 0xc0) { | |
| if (remaining > 0) { | |
| --remaining; | |
| code_point = (code_point << 6) | (code_unit & 0x3f); | |
| if (remaining == 0) { | |
| AppendCodePointToWideString(code_point, buffer); | |
| } | |
| } | |
| } else if (code_unit < 0xe0) { | |
| remaining = 1; | |
| code_point = code_unit & 0x1f; | |
| } else if (code_unit < 0xf0) { | |
| remaining = 2; | |
| code_point = code_unit & 0x0f; | |
| } else if (code_unit < 0xf8) { | |
| remaining = 3; | |
| code_point = code_unit & 0x07; | |
| } else { | |
| remaining = 0; | |
| } | |
| } | |
| return buffer; | |
| } | |
| namespace { | |
| constexpr float kFractionScalesFloat[] = { | |
| 0.1f, 0.01f, 0.001f, 0.0001f, | |
| 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, | |
| 0.000000001f, 0.0000000001f, 0.00000000001f}; | |
| const double kFractionScalesDouble[] = { | |
| 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, | |
| 0.0000001, 0.00000001, 0.000000001, 0.0000000001, 0.00000000001}; | |
| template <class T> | |
| T StringTo(ByteStringView strc, pdfium::span<const T> fractional_scales) { | |
| if (strc.IsEmpty()) | |
| return 0; | |
| bool bNegative = false; | |
| size_t cc = 0; | |
| size_t len = strc.GetLength(); | |
| if (strc[0] == '+') { | |
| cc++; | |
| } else if (strc[0] == '-') { | |
| bNegative = true; | |
| cc++; | |
| } | |
| while (cc < len) { | |
| if (strc[cc] != '+' && strc[cc] != '-') | |
| break; | |
| cc++; | |
| } | |
| T value = 0; | |
| while (cc < len) { | |
| if (strc[cc] == '.') | |
| break; | |
| value = value * 10 + FXSYS_DecimalCharToInt(strc.CharAt(cc)); | |
| cc++; | |
| } | |
| size_t scale = 0; | |
| if (cc < len && strc[cc] == '.') { | |
| cc++; | |
| while (cc < len) { | |
| value += | |
| fractional_scales[scale] * FXSYS_DecimalCharToInt(strc.CharAt(cc)); | |
| scale++; | |
| if (scale == fractional_scales.size()) | |
| break; | |
| cc++; | |
| } | |
| } | |
| return bNegative ? -value : value; | |
| } | |
| template <class T> | |
| size_t ToString(T value, int (*round_func)(T), pdfium::span<char> buf) { | |
| buf[0] = '0'; | |
| buf[1] = '\0'; | |
| if (value == 0) { | |
| return 1; | |
| } | |
| bool bNegative = false; | |
| if (value < 0) { | |
| bNegative = true; | |
| value = -value; | |
| } | |
| int scale = 1; | |
| int scaled = round_func(value); | |
| while (scaled < 100000) { | |
| if (scale == 1000000) { | |
| break; | |
| } | |
| scale *= 10; | |
| scaled = round_func(value * scale); | |
| } | |
| if (scaled == 0) { | |
| return 1; | |
| } | |
| char buf2[32]; | |
| size_t buf_size = 0; | |
| if (bNegative) { | |
| buf[buf_size++] = '-'; | |
| } | |
| int i = scaled / scale; | |
| FXSYS_itoa(i, buf2, 10); | |
| size_t len = strlen(buf2); | |
| fxcrt::spancpy(buf.subspan(buf_size), pdfium::make_span(buf2).first(len)); | |
| buf_size += len; | |
| int fraction = scaled % scale; | |
| if (fraction == 0) { | |
| return buf_size; | |
| } | |
| buf[buf_size++] = '.'; | |
| scale /= 10; | |
| while (fraction) { | |
| buf[buf_size++] = '0' + fraction / scale; | |
| fraction %= scale; | |
| scale /= 10; | |
| } | |
| return buf_size; | |
| } | |
| } // namespace | |
| float StringToFloat(ByteStringView strc) { | |
| return StringTo<float>(strc, kFractionScalesFloat); | |
| } | |
| float StringToFloat(WideStringView wsStr) { | |
| return StringToFloat(FX_UTF8Encode(wsStr).AsStringView()); | |
| } | |
| size_t FloatToString(float f, pdfium::span<char> buf) { | |
| return ToString<float>(f, FXSYS_roundf, buf); | |
| } | |
| double StringToDouble(ByteStringView strc) { | |
| return StringTo<double>(strc, kFractionScalesDouble); | |
| } | |
| double StringToDouble(WideStringView wsStr) { | |
| return StringToDouble(FX_UTF8Encode(wsStr).AsStringView()); | |
| } | |
| size_t DoubleToString(double d, pdfium::span<char> buf) { | |
| return ToString<double>(d, FXSYS_round, buf); | |
| } | |
| namespace fxcrt { | |
| template std::vector<ByteString> Split<ByteString>(const ByteString& that, | |
| ByteString::CharType ch); | |
| template std::vector<WideString> Split<WideString>(const WideString& that, | |
| WideString::CharType ch); | |
| } // namespace fxcrt |