1 //========================================================================
2 //
3 // This file is under the GPLv2 or later license
4 //
5 // Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
6 // Copyright (C) 2005, 2009, 2014, 2019, 2020 Albert Astals Cid <aacid@kde.org>
7 // Copyright (C) 2011 Simon Kellner <kellner@kit.edu>
8 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
9 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
10 // Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
11 //
12 // To see a description of the changes please see the Changelog file that
13 // came with your tarball or type make ChangeLog if you are building from git
14 //
15 //========================================================================
16
17 #ifndef PAGELABELINFO_P_H
18 #define PAGELABELINFO_P_H
19
20 /* http://mathworld.wolfram.com/RomanNumerals.html */
21
22 #include "config.h"
23
24 #include "goo/GooString.h"
25 #include "Error.h"
26
fromDecimal(const std::string & str,const bool unicode)27 static std::pair<int, bool> fromDecimal(const std::string &str, const bool unicode)
28 {
29 if (unicode && (str.size() % 2 == 0)) {
30 if (GooString::hasUnicodeMarker(str)) {
31 // strip the marker if it is there
32 return fromDecimal(str.substr(2), true /*unicode*/);
33 }
34
35 // Since we only care about numbers here, the first byte needs to be
36 // 0 and second will be the actual ascii number, so we're going to reconstruct a
37 // non unicode string that then we will use strtol to "translate"
38 std::string newString;
39 bool allGood = true;
40 for (size_t i = 0; allGood && i < str.size(); i += 2) {
41 if (str[i] == 0) {
42 newString += str[i + 1];
43 } else {
44 allGood = false;
45 }
46 }
47
48 if (allGood) {
49 return fromDecimal(newString, false /*unicode*/);
50 }
51 }
52
53 const char *const begin = str.data();
54 const char *const end = begin + str.size();
55
56 char *parsed;
57 const int number = std::strtol(begin, &parsed, 10);
58 return std::make_pair(number, parsed >= end);
59 }
60
fromRoman(const char * buffer)61 static int fromRoman(const char *buffer)
62 {
63 int digit_value, prev_digit_value, value;
64 int i;
65
66 prev_digit_value = INT_MAX;
67 value = 0;
68 for (i = 0; buffer[i] != '\0'; i++) {
69 switch (buffer[i]) {
70 case 'm':
71 case 'M':
72 digit_value = 1000;
73 break;
74 case 'd':
75 case 'D':
76 digit_value = 500;
77 break;
78 case 'c':
79 case 'C':
80 digit_value = 100;
81 break;
82 case 'l':
83 case 'L':
84 digit_value = 50;
85 break;
86 case 'x':
87 case 'X':
88 digit_value = 10;
89 break;
90 case 'v':
91 case 'V':
92 digit_value = 5;
93 break;
94 case 'i':
95 case 'I':
96 digit_value = 1;
97 break;
98 default:
99 return -1;
100 }
101
102 if (digit_value <= prev_digit_value)
103 value += digit_value;
104 else
105 value += digit_value - prev_digit_value * 2;
106 prev_digit_value = digit_value;
107 }
108
109 return value;
110 }
111
toRoman(int number,GooString * str,bool uppercase)112 static void toRoman(int number, GooString *str, bool uppercase)
113 {
114 static const char uppercaseNumerals[] = "IVXLCDM";
115 static const char lowercaseNumerals[] = "ivxlcdm";
116 int divisor;
117 int i, j, k;
118 const char *wh;
119
120 if (number >= 4000) {
121 error(errUnimplemented, -1, "Conversion to roman numerals of numbers >= 4000 not implemented");
122 return;
123 }
124
125 if (uppercase)
126 wh = uppercaseNumerals;
127 else
128 wh = lowercaseNumerals;
129
130 divisor = 1000;
131 for (k = 3; k >= 0; k--) {
132 i = number / divisor;
133 number = number % divisor;
134
135 switch (i) {
136 case 0:
137 break;
138 case 5:
139 str->append(wh[2 * k + 1]);
140 break;
141 case 9:
142 str->append(wh[2 * k + 0]);
143 str->append(wh[2 * k + 2]);
144 break;
145 case 4:
146 str->append(wh[2 * k + 0]);
147 str->append(wh[2 * k + 1]);
148 break;
149 default:
150 if (i > 5) {
151 str->append(wh[2 * k + 1]);
152 i -= 5;
153 }
154 for (j = 0; j < i; j++) {
155 str->append(wh[2 * k + 0]);
156 }
157 }
158
159 divisor = divisor / 10;
160 }
161 }
162
fromLatin(const char * buffer)163 static int fromLatin(const char *buffer)
164 {
165 int count;
166 const char *p;
167
168 for (p = buffer; *p; p++) {
169 if (*p != buffer[0])
170 return -1;
171 }
172
173 count = p - buffer;
174 if (buffer[0] >= 'a' && buffer[0] <= 'z')
175 return 26 * (count - 1) + buffer[0] - 'a' + 1;
176 if (buffer[0] >= 'A' && buffer[0] <= 'Z')
177 return 26 * (count - 1) + buffer[0] - 'A' + 1;
178
179 return -1;
180 }
181
toLatin(int number,GooString * str,bool uppercase)182 static void toLatin(int number, GooString *str, bool uppercase)
183 {
184 char base, letter;
185 int i, count;
186
187 if (uppercase)
188 base = 'A';
189 else
190 base = 'a';
191
192 count = (number - 1) / 26 + 1;
193 letter = base + (number - 1) % 26;
194
195 for (i = 0; i < count; i++)
196 str->append(letter);
197 }
198
199 #endif
200