source: trunk/poppler/mypoppler/poppler/PageLabelInfo.cc @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

File size: 7.8 KB
Line 
1#include <limits.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <assert.h>
5#include "UGooString.h"
6
7#include "PageLabelInfo.h"
8
9/* http://mathworld.wolfram.com/RomanNumerals.html */
10
11static int fromRoman(const char *buffer) {
12  int digit_value, prev_digit_value, value;
13  int i;
14
15  prev_digit_value = INT_MAX;
16  value = 0;
17  for (i = 0; buffer[i] != '\0'; i++) {
18    switch (buffer[i]) {
19    case 'm':
20    case 'M':
21      digit_value = 1000;
22      break;
23    case 'd':
24    case 'D':
25      digit_value = 500;
26      break;
27    case 'c':
28    case 'C':
29      digit_value = 100;
30      break;
31    case 'l':
32    case 'L':
33      digit_value = 50;
34      break;
35    case 'x':
36    case 'X':
37      digit_value = 10;
38      break;
39    case 'v':
40    case 'V':
41      digit_value = 5;
42      break;
43    case 'i':
44    case 'I':
45      digit_value = 1;
46      break;
47    default:
48      return -1;
49    }
50
51    if (digit_value <= prev_digit_value)
52      value += digit_value;
53    else
54      value += digit_value - prev_digit_value * 2;
55    prev_digit_value = digit_value;
56  }
57
58  return value;
59}
60
61static void toRoman(int number, GooString *str, GBool uppercase) {
62  static const char uppercaseNumerals[] = "IVXLCDM";
63  static const char lowercaseNumerals[] = "ivxlcdm";
64  int divisor;
65  int i, j, k;
66  const char *wh;
67
68  if (uppercase)
69    wh = uppercaseNumerals;
70  else
71    wh = lowercaseNumerals;
72
73  divisor = 1000;
74  for (k = 3; k >= 0; k--) {
75    i = number / divisor;
76    number = number % divisor;
77
78    switch (i) {
79    case 0:
80      break;
81    case 5:
82      str->append(wh[2 * k + 1]);
83      break;
84    case 9:
85      str->append(wh[2 * k + 0]);
86      str->append(wh[ 2 * k + 2]);
87      break;
88    case 4:
89      str->append(wh[2 * k + 0]);
90      str->append(wh[2 * k + 1]);
91      break;
92    default:
93      if (i > 5) {
94        str->append(wh[2 * k + 1]);
95        i -= 5;
96      }
97      for (j = 0; j < i; j++) {
98        str->append(wh[2 * k + 0]);
99      }
100    }
101       
102    divisor = divisor / 10;
103  }
104}
105
106static int fromLatin(const char *buffer)
107{
108  int count;
109  const char *p;
110
111  for (p = buffer; *p; p++) {
112    if (*p != buffer[0])
113      return -1;
114  }
115
116  count = p - buffer;
117  if (buffer[0] >= 'a' && buffer[0] <= 'z')
118    return 26 * (count - 1) + buffer[0] - 'a' + 1;
119  if (buffer[0] >= 'A' && buffer[0] <= 'Z')
120    return 26 * (count - 1) + buffer[0] - 'A' + 1;
121
122  return -1;
123}
124
125static void toLatin(int number, GooString *str, GBool uppercase) {
126  char base, letter;
127  int i, count;
128
129  if (uppercase)
130    base = 'A';
131  else
132    base = 'a';
133
134  count = (number - 1) / 26 + 1;
135  letter = base + (number - 1) % 26;
136
137  for (i = 0; i < count; i++)
138    str->append(letter);
139}
140
141PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
142  Object obj;
143
144  style = None;
145  if (dict->dictLookup("S", &obj)->isName()) {
146    if (obj.isName("D")) {
147      style = Arabic;
148    } else if (obj.isName("R")) {
149      style = UppercaseRoman;
150    } else if (obj.isName("r")) {
151      style = LowercaseRoman;
152    } else if (obj.isName("A")) {
153      style = UppercaseLatin;
154    } else if (obj.isName("a")) {
155      style = LowercaseLatin;
156    }
157  }
158  obj.free();
159
160  if (dict->dictLookup("P", &obj)->isString())
161    prefix = obj.getString()->copy();
162  else
163    prefix = new GooString("");
164  obj.free();
165
166  if (dict->dictLookup("St", &obj)->isInt())
167    first = obj.getInt();
168  else
169    first = 1;
170  obj.free();
171
172  base = baseA;
173}
174
175PageLabelInfo::Interval::~Interval() {
176  delete prefix;
177}
178
179PageLabelInfo::PageLabelInfo(Object *tree, int numPages) {
180  int i;
181  Interval *interval, *next;
182
183  parse(tree);
184
185  for (i = 0; i < intervals.getLength(); i++) {
186    interval = (Interval *) intervals.get(i);
187
188    if (i + 1 < intervals.getLength()) {
189      next = (Interval *) intervals.get(i + 1);
190      interval->length = next->base - interval->base;
191    } else {
192      interval->length = numPages - interval->base;
193    }
194  }
195}
196
197PageLabelInfo::~PageLabelInfo() {
198  int i;
199  for (i = 0; i < intervals.getLength(); ++i) {
200    delete (Interval*)intervals.get(i);
201  }
202}
203
204void PageLabelInfo::parse(Object *tree) {
205  Object nums, obj;
206  Object kids, kid, limits, low, high;
207  int i, base;
208  Interval *interval;
209
210  // leaf node
211  if (tree->dictLookup("Nums", &nums)->isArray()) {
212    for (i = 0; i < nums.arrayGetLength(); i += 2) {
213      if (!nums.arrayGet(i, &obj)->isInt()) {
214        obj.free();
215        continue;
216      }
217      base = obj.getInt();
218      obj.free();
219      if (!nums.arrayGet(i + 1, &obj)->isDict()) {
220        obj.free();
221        continue;
222      }
223
224      interval = new Interval(&obj, base);
225      obj.free();
226      intervals.append(interval);
227    }
228  }
229  nums.free();
230
231  if (tree->dictLookup("Kids", &kids)->isArray()) {
232    for (i = 0; i < kids.arrayGetLength(); ++i) {
233      if (kids.arrayGet(i, &kid)->isDict())
234        parse(&kid);
235      kid.free();
236    }
237  }
238  kids.free();
239}
240
241GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
242{
243  Interval *interval;
244  char *str = label->getCString(), *end;
245  int prefixLength;
246  int i, base, number;
247
248  base = 0;
249  for (i = 0; i < intervals.getLength(); i++) {
250    interval = (Interval *) intervals.get(i);
251    prefixLength = interval->prefix->getLength();
252    if (label->cmpN(interval->prefix, prefixLength) != 0)
253      continue;
254
255    switch (interval->style) {
256    case Interval::Arabic:
257      number = strtol(str + prefixLength, &end, 10);
258      if (*end == '\0' && number - interval->first < interval->length) {
259        *index = base + number - interval->first;
260        return gTrue;
261      }
262      break;
263    case Interval::LowercaseRoman:
264    case Interval::UppercaseRoman:
265      number = fromRoman(str + prefixLength);
266      if (number >= 0 && number - interval->first < interval->length) {
267        *index = base + number - interval->first;
268        return gTrue;
269      }
270      break;
271    case Interval::UppercaseLatin:
272    case Interval::LowercaseLatin:
273      number = fromLatin(str + prefixLength);
274      if (number >= 0 && number - interval->first < interval->length) {
275        *index = base + number - interval->first;
276        return gTrue;
277      }
278      break;
279    case Interval::None:
280      break;
281    }
282
283    base += interval->length;
284  }
285
286  return gFalse;
287}
288
289GBool PageLabelInfo::indexToLabel(int index, GooString *label)
290{
291  char buffer[32];
292  int i, base, number;
293  Interval *interval;
294  GooString number_string;
295
296  base = 0;
297  interval = NULL;
298  for (i = 0; i < intervals.getLength(); i++) {
299    interval = (Interval *) intervals.get(i);
300    if (base <= index && index < base + interval->length)
301      break;
302    base += interval->length;
303  }
304
305  if (i == intervals.getLength())
306    return gFalse;
307
308  number = index - base + interval->first;
309  switch (interval->style) {
310  case Interval::Arabic:
311    snprintf (buffer, sizeof(buffer), "%d", number);
312    number_string.append(buffer);
313    break;
314  case Interval::LowercaseRoman:
315    toRoman(number, &number_string, gFalse);
316    break;
317  case Interval::UppercaseRoman:
318    toRoman(number, &number_string, gTrue);
319    break;
320  case Interval::UppercaseLatin:
321  case Interval::LowercaseLatin:
322    number = 0;
323    break;
324  case Interval::None:
325    break;
326  }
327
328  label->clear();
329  label->append(interval->prefix);
330  if (label->hasUnicodeMarker()) {
331      int i, len;
332      char ucs2_char[2];
333
334      /* Convert the ascii number string to ucs2 and append. */
335      len = number_string.getLength ();
336      ucs2_char[0] = 0;
337      for (i = 0; i < len; ++i) {
338          ucs2_char[1] = number_string.getChar(i);
339          label->append(ucs2_char, 2);
340      }
341      ucs2_char[1] = 0;
342      label->append(ucs2_char, 2);
343  } else {
344      label->append(&number_string);
345  }
346
347  return gTrue;
348}
349
350#ifdef TEST
351int main(int argc, char *argv[])
352{
353  {
354    GooString str;
355    toRoman(177, &str, gFalse);
356    assert (str.cmp("clxxvii") == 0);
357  }
358
359  {
360    GooString roman("clxxvii");
361    assert (fromRoman(roman.getCString()) == 177);
362  }
363
364  {
365    GooString str;
366    toLatin(54, &str, gFalse);
367    assert (str.cmp("bbb") == 0);
368  }
369
370  {
371    GooString latin("ddd");
372    assert (fromLatin(latin.getCString()) == 56);
373  }
374}
375#endif
Note: See TracBrowser for help on using the repository browser.