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, 2022 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, 2024 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#include "UTF.h"
27
28static std::pair<int, bool> fromDecimal(const std::string &str, const bool unicode)
29{
30 if (unicode && (str.size() % 2 == 0)) {
31 if (hasUnicodeByteOrderMark(s: str)) {
32 // strip the marker if it is there
33 return fromDecimal(str: str.substr(pos: 2), unicode: true /*unicode*/);
34 }
35
36 // Since we only care about numbers here, the first byte needs to be
37 // 0 and second will be the actual ascii number, so we're going to reconstruct a
38 // non unicode string that then we will use strtol to "translate"
39 std::string newString;
40 bool allGood = true;
41 for (size_t i = 0; allGood && i < str.size(); i += 2) {
42 if (str[i] == 0) {
43 newString += str[i + 1];
44 } else {
45 allGood = false;
46 }
47 }
48
49 if (allGood) {
50 return fromDecimal(str: newString, unicode: false /*unicode*/);
51 }
52 }
53
54 const char *const begin = str.data();
55 const char *const end = begin + str.size();
56
57 char *parsed;
58 const int number = std::strtol(nptr: begin, endptr: &parsed, base: 10);
59 return std::make_pair(x: number, y: parsed >= end);
60}
61
62static int fromRoman(const char *buffer)
63{
64 int digit_value, prev_digit_value, value;
65 int i;
66
67 prev_digit_value = INT_MAX;
68 value = 0;
69 for (i = 0; buffer[i] != '\0'; i++) {
70 switch (buffer[i]) {
71 case 'm':
72 case 'M':
73 digit_value = 1000;
74 break;
75 case 'd':
76 case 'D':
77 digit_value = 500;
78 break;
79 case 'c':
80 case 'C':
81 digit_value = 100;
82 break;
83 case 'l':
84 case 'L':
85 digit_value = 50;
86 break;
87 case 'x':
88 case 'X':
89 digit_value = 10;
90 break;
91 case 'v':
92 case 'V':
93 digit_value = 5;
94 break;
95 case 'i':
96 case 'I':
97 digit_value = 1;
98 break;
99 default:
100 return -1;
101 }
102
103 if (digit_value <= prev_digit_value) {
104 value += digit_value;
105 } else {
106 value += digit_value - prev_digit_value * 2;
107 }
108 prev_digit_value = digit_value;
109 }
110
111 return value;
112}
113
114static void toRoman(int number, GooString *str, bool uppercase)
115{
116 static const char uppercaseNumerals[] = "IVXLCDM";
117 static const char lowercaseNumerals[] = "ivxlcdm";
118 int divisor;
119 int i, j, k;
120 const char *wh;
121
122 if (number >= 4000) {
123 error(category: errUnimplemented, pos: -1, msg: "Conversion to roman numerals of numbers >= 4000 not implemented");
124 return;
125 }
126
127 if (uppercase) {
128 wh = uppercaseNumerals;
129 } else {
130 wh = lowercaseNumerals;
131 }
132
133 divisor = 1000;
134 for (k = 3; k >= 0; k--) {
135 i = number / divisor;
136 number = number % divisor;
137
138 switch (i) {
139 case 0:
140 break;
141 case 5:
142 str->append(c: wh[2 * k + 1]);
143 break;
144 case 9:
145 str->append(c: wh[2 * k + 0]);
146 str->append(c: wh[2 * k + 2]);
147 break;
148 case 4:
149 str->append(c: wh[2 * k + 0]);
150 str->append(c: wh[2 * k + 1]);
151 break;
152 default:
153 if (i > 5) {
154 str->append(c: wh[2 * k + 1]);
155 i -= 5;
156 }
157 for (j = 0; j < i; j++) {
158 str->append(c: wh[2 * k + 0]);
159 }
160 }
161
162 divisor = divisor / 10;
163 }
164}
165
166static int fromLatin(const char *buffer)
167{
168 const char *p;
169
170 for (p = buffer; *p; p++) {
171 if (*p != buffer[0]) {
172 return -1;
173 }
174 }
175
176 const intptr_t diff = p - buffer;
177 if (unlikely(diff > std::numeric_limits<int>::max() / 100)) {
178 error(category: errUnimplemented, pos: -1, msg: "Something went wrong in fromLatin conversion");
179 return -1;
180 }
181 const int count = static_cast<int>(diff);
182 if (buffer[0] >= 'a' && buffer[0] <= 'z') {
183 return 26 * (count - 1) + buffer[0] - 'a' + 1;
184 }
185 if (buffer[0] >= 'A' && buffer[0] <= 'Z') {
186 return 26 * (count - 1) + buffer[0] - 'A' + 1;
187 }
188
189 return -1;
190}
191
192static void toLatin(int number, GooString *str, bool uppercase)
193{
194 char base, letter;
195 int i, count;
196
197 if (uppercase) {
198 base = 'A';
199 } else {
200 base = 'a';
201 }
202
203 count = (number - 1) / 26 + 1;
204 letter = base + (number - 1) % 26;
205
206 for (i = 0; i < count; i++) {
207 str->append(c: letter);
208 }
209}
210
211#endif
212

source code of poppler/poppler/PageLabelInfo_p.h