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

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

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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.