//======================================================================== // // This file is under the GPLv2 or later license // // Copyright (C) 2005-2006 Kristian Høgsberg // Copyright (C) 2005, 2009, 2014, 2019, 2020 Albert Astals Cid // Copyright (C) 2011 Simon Kellner // Copyright (C) 2012 Fabio D'Urso // Copyright (C) 2018 Adam Reichold // Copyright (C) 2019 Oliver Sander // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git // //======================================================================== #ifndef PAGELABELINFO_P_H #define PAGELABELINFO_P_H /* http://mathworld.wolfram.com/RomanNumerals.html */ #include "config.h" #ifdef HAVE_CODECVT # include # include #endif #include "goo/GooString.h" #include "Error.h" static std::pair fromDecimal(const char *const begin, const char *const end, const bool unicode) { #ifdef HAVE_CODECVT if (unicode) { std::wstring_convert> converter("", L""); const auto str = converter.from_bytes(begin, end); // Skip BOM since wcstol seems unable to handle it. const wchar_t *c_str = str.c_str(); if (*c_str == wchar_t { 0xfeff }) { ++c_str; } wchar_t *parsed; const int number = std::wcstol(c_str, &parsed, 10); if (parsed >= str.data() + str.size()) { return std::make_pair(number, true); } } #else (void)unicode; #endif char *parsed; const int number = std::strtol(begin, &parsed, 10); return std::make_pair(number, parsed >= end); } static int fromRoman(const char *buffer) { int digit_value, prev_digit_value, value; int i; prev_digit_value = INT_MAX; value = 0; for (i = 0; buffer[i] != '\0'; i++) { switch (buffer[i]) { case 'm': case 'M': digit_value = 1000; break; case 'd': case 'D': digit_value = 500; break; case 'c': case 'C': digit_value = 100; break; case 'l': case 'L': digit_value = 50; break; case 'x': case 'X': digit_value = 10; break; case 'v': case 'V': digit_value = 5; break; case 'i': case 'I': digit_value = 1; break; default: return -1; } if (digit_value <= prev_digit_value) value += digit_value; else value += digit_value - prev_digit_value * 2; prev_digit_value = digit_value; } return value; } static void toRoman(int number, GooString *str, bool uppercase) { static const char uppercaseNumerals[] = "IVXLCDM"; static const char lowercaseNumerals[] = "ivxlcdm"; int divisor; int i, j, k; const char *wh; if (number >= 4000) { error(errUnimplemented, -1, "Conversion to roman numerals of numbers >= 4000 not implemented"); return; } if (uppercase) wh = uppercaseNumerals; else wh = lowercaseNumerals; divisor = 1000; for (k = 3; k >= 0; k--) { i = number / divisor; number = number % divisor; switch (i) { case 0: break; case 5: str->append(wh[2 * k + 1]); break; case 9: str->append(wh[2 * k + 0]); str->append(wh[2 * k + 2]); break; case 4: str->append(wh[2 * k + 0]); str->append(wh[2 * k + 1]); break; default: if (i > 5) { str->append(wh[2 * k + 1]); i -= 5; } for (j = 0; j < i; j++) { str->append(wh[2 * k + 0]); } } divisor = divisor / 10; } } static int fromLatin(const char *buffer) { int count; const char *p; for (p = buffer; *p; p++) { if (*p != buffer[0]) return -1; } count = p - buffer; if (buffer[0] >= 'a' && buffer[0] <= 'z') return 26 * (count - 1) + buffer[0] - 'a' + 1; if (buffer[0] >= 'A' && buffer[0] <= 'Z') return 26 * (count - 1) + buffer[0] - 'A' + 1; return -1; } static void toLatin(int number, GooString *str, bool uppercase) { char base, letter; int i, count; if (uppercase) base = 'A'; else base = 'a'; count = (number - 1) / 26 + 1; letter = base + (number - 1) % 26; for (i = 0; i < count; i++) str->append(letter); } #endif