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

Last change on this file since 257 was 257, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.0

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