1
//========================================================================
3
// This file is under the GPLv2 or later license
5
// Copyright (C) 2005-2006 Kristian HĆøgsberg <krh@redhat.com>
6
// Copyright (C) 2005, 2009 Albert Astals Cid <aacid@kde.org>
8
// To see a description of the changes please see the Changelog file that
9
// came with your tarball or type make ChangeLog if you are building from git
11
//========================================================================
19
#include "PageLabelInfo.h"
21
/* http://mathworld.wolfram.com/RomanNumerals.html */
23
static int fromRoman(const char *buffer) {
24
int digit_value, prev_digit_value, value;
27
prev_digit_value = INT_MAX;
29
for (i = 0; buffer[i] != '\0'; i++) {
63
if (digit_value <= prev_digit_value)
66
value += digit_value - prev_digit_value * 2;
67
prev_digit_value = digit_value;
73
static void toRoman(int number, GooString *str, GBool uppercase) {
74
static const char uppercaseNumerals[] = "IVXLCDM";
75
static const char lowercaseNumerals[] = "ivxlcdm";
81
wh = uppercaseNumerals;
83
wh = lowercaseNumerals;
86
for (k = 3; k >= 0; k--) {
88
number = number % divisor;
94
str->append(wh[2 * k + 1]);
97
str->append(wh[2 * k + 0]);
98
str->append(wh[ 2 * k + 2]);
101
str->append(wh[2 * k + 0]);
102
str->append(wh[2 * k + 1]);
106
str->append(wh[2 * k + 1]);
109
for (j = 0; j < i; j++) {
110
str->append(wh[2 * k + 0]);
114
divisor = divisor / 10;
118
static int fromLatin(const char *buffer)
123
for (p = buffer; *p; p++) {
129
if (buffer[0] >= 'a' && buffer[0] <= 'z')
130
return 26 * (count - 1) + buffer[0] - 'a' + 1;
131
if (buffer[0] >= 'A' && buffer[0] <= 'Z')
132
return 26 * (count - 1) + buffer[0] - 'A' + 1;
138
static void toLatin(int number, GooString *str, GBool uppercase) {
147
count = (number - 1) / 26 + 1;
148
letter = base + (number - 1) % 26;
150
for (i = 0; i < count; i++)
155
PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
159
if (dict->dictLookup("S", &obj)->isName()) {
160
if (obj.isName("D")) {
162
} else if (obj.isName("R")) {
163
style = UppercaseRoman;
164
} else if (obj.isName("r")) {
165
style = LowercaseRoman;
166
} else if (obj.isName("A")) {
167
style = UppercaseLatin;
168
} else if (obj.isName("a")) {
169
style = LowercaseLatin;
174
if (dict->dictLookup("P", &obj)->isString())
175
prefix = obj.getString()->copy();
177
prefix = new GooString("");
180
if (dict->dictLookup("St", &obj)->isInt())
181
first = obj.getInt();
189
PageLabelInfo::Interval::~Interval() {
193
PageLabelInfo::PageLabelInfo(Object *tree, int numPages) {
195
Interval *interval, *next;
199
for (i = 0; i < intervals.getLength(); i++) {
200
interval = (Interval *) intervals.get(i);
202
if (i + 1 < intervals.getLength()) {
203
next = (Interval *) intervals.get(i + 1);
204
interval->length = next->base - interval->base;
206
interval->length = numPages - interval->base;
208
if (interval->length < 0) interval->length = 0;
212
PageLabelInfo::~PageLabelInfo() {
214
for (i = 0; i < intervals.getLength(); ++i) {
215
delete (Interval*)intervals.get(i);
219
void PageLabelInfo::parse(Object *tree) {
221
Object kids, kid, limits, low, high;
226
if (tree->dictLookup("Nums", &nums)->isArray()) {
227
for (i = 0; i < nums.arrayGetLength(); i += 2) {
228
if (!nums.arrayGet(i, &obj)->isInt()) {
234
if (!nums.arrayGet(i + 1, &obj)->isDict()) {
239
interval = new Interval(&obj, base);
241
intervals.append(interval);
246
if (tree->dictLookup("Kids", &kids)->isArray()) {
247
for (i = 0; i < kids.arrayGetLength(); ++i) {
248
if (kids.arrayGet(i, &kid)->isDict())
256
GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
259
char *str = label->getCString(), *end;
264
for (i = 0; i < intervals.getLength(); i++) {
265
interval = (Interval *) intervals.get(i);
266
prefixLength = interval->prefix->getLength();
267
if (label->cmpN(interval->prefix, prefixLength) != 0)
270
switch (interval->style) {
271
case Interval::Arabic:
272
number = strtol(str + prefixLength, &end, 10);
273
if (*end == '\0' && number - interval->first < interval->length) {
274
*index = base + number - interval->first;
278
case Interval::LowercaseRoman:
279
case Interval::UppercaseRoman:
280
number = fromRoman(str + prefixLength);
281
if (number >= 0 && number - interval->first < interval->length) {
282
*index = base + number - interval->first;
286
case Interval::UppercaseLatin:
287
case Interval::LowercaseLatin:
288
number = fromLatin(str + prefixLength);
289
if (number >= 0 && number - interval->first < interval->length) {
290
*index = base + number - interval->first;
298
base += interval->length;
304
GBool PageLabelInfo::indexToLabel(int index, GooString *label)
309
GooString number_string;
313
for (i = 0; i < intervals.getLength(); i++) {
314
interval = (Interval *) intervals.get(i);
315
if (base <= index && index < base + interval->length)
317
base += interval->length;
320
if (i == intervals.getLength())
323
number = index - base + interval->first;
324
switch (interval->style) {
325
case Interval::Arabic:
326
snprintf (buffer, sizeof(buffer), "%d", number);
327
number_string.append(buffer);
329
case Interval::LowercaseRoman:
330
toRoman(number, &number_string, gFalse);
332
case Interval::UppercaseRoman:
333
toRoman(number, &number_string, gTrue);
335
case Interval::UppercaseLatin:
336
case Interval::LowercaseLatin:
344
label->append(interval->prefix);
345
if (label->hasUnicodeMarker()) {
349
/* Convert the ascii number string to ucs2 and append. */
350
len = number_string.getLength ();
352
for (i = 0; i < len; ++i) {
353
ucs2_char[1] = number_string.getChar(i);
354
label->append(ucs2_char, 2);
357
label->append(ucs2_char, 2);
359
label->append(&number_string);
366
int main(int argc, char *argv[])
370
toRoman(177, &str, gFalse);
371
assert (str.cmp("clxxvii") == 0);
375
GooString roman("clxxvii");
376
assert (fromRoman(roman.getCString()) == 177);
381
toLatin(54, &str, gFalse);
382
assert (str.cmp("bbb") == 0);
386
GooString latin("ddd");
387
assert (fromLatin(latin.getCString()) == 56);