~ubuntu-branches/ubuntu/oneiric/luatex/oneiric

« back to all changes in this revision

Viewing changes to source/libs/poppler/poppler-0.12.4/poppler/PageLabelInfo.cc

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2011-04-10 21:08:04 UTC
  • mfrom: (0.3.1) (1.6.1) (19.1.5 natty)
  • Revision ID: package-import@ubuntu.com-20110410210804-m979ehyw4hnzvhu3
Tags: 0.65.0-1ubuntu3
RebuildĀ againstĀ libpoppler13.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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
 
 
23
static 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
 
 
73
static 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
 
 
118
static 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
 
138
static 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
 
 
155
PageLabelInfo::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
 
 
189
PageLabelInfo::Interval::~Interval() {
 
190
  delete prefix;
 
191
}
 
192
 
 
193
PageLabelInfo::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
    if (interval->length < 0) interval->length = 0;
 
209
  }
 
210
}
 
211
 
 
212
PageLabelInfo::~PageLabelInfo() {
 
213
  int i;
 
214
  for (i = 0; i < intervals.getLength(); ++i) {
 
215
    delete (Interval*)intervals.get(i);
 
216
  }
 
217
}
 
218
 
 
219
void PageLabelInfo::parse(Object *tree) {
 
220
  Object nums, obj;
 
221
  Object kids, kid, limits, low, high;
 
222
  int i, base;
 
223
  Interval *interval;
 
224
 
 
225
  // leaf node
 
226
  if (tree->dictLookup("Nums", &nums)->isArray()) {
 
227
    for (i = 0; i < nums.arrayGetLength(); i += 2) {
 
228
      if (!nums.arrayGet(i, &obj)->isInt()) {
 
229
        obj.free();
 
230
        continue;
 
231
      }
 
232
      base = obj.getInt();
 
233
      obj.free();
 
234
      if (!nums.arrayGet(i + 1, &obj)->isDict()) {
 
235
        obj.free();
 
236
        continue;
 
237
      }
 
238
 
 
239
      interval = new Interval(&obj, base);
 
240
      obj.free();
 
241
      intervals.append(interval);
 
242
    }
 
243
  }
 
244
  nums.free();
 
245
 
 
246
  if (tree->dictLookup("Kids", &kids)->isArray()) {
 
247
    for (i = 0; i < kids.arrayGetLength(); ++i) {
 
248
      if (kids.arrayGet(i, &kid)->isDict())
 
249
        parse(&kid);
 
250
      kid.free();
 
251
    }
 
252
  }
 
253
  kids.free();
 
254
}
 
255
 
 
256
GBool PageLabelInfo::labelToIndex(GooString *label, int *index)
 
257
{
 
258
  Interval *interval;
 
259
  char *str = label->getCString(), *end;
 
260
  int prefixLength;
 
261
  int i, base, number;
 
262
 
 
263
  base = 0;
 
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)
 
268
      continue;
 
269
 
 
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;
 
275
        return gTrue;
 
276
      }
 
277
      break;
 
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;
 
283
        return gTrue;
 
284
      }
 
285
      break;
 
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;
 
291
        return gTrue;
 
292
      }
 
293
      break;
 
294
    case Interval::None:
 
295
      break;
 
296
    }
 
297
 
 
298
    base += interval->length;
 
299
  }
 
300
 
 
301
  return gFalse;
 
302
}
 
303
 
 
304
GBool PageLabelInfo::indexToLabel(int index, GooString *label)
 
305
{
 
306
  char buffer[32];
 
307
  int i, base, number;
 
308
  Interval *interval;
 
309
  GooString number_string;
 
310
 
 
311
  base = 0;
 
312
  interval = NULL;
 
313
  for (i = 0; i < intervals.getLength(); i++) {
 
314
    interval = (Interval *) intervals.get(i);
 
315
    if (base <= index && index < base + interval->length)
 
316
      break;
 
317
    base += interval->length;
 
318
  }
 
319
 
 
320
  if (i == intervals.getLength())
 
321
    return gFalse;
 
322
 
 
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);
 
328
    break;
 
329
  case Interval::LowercaseRoman:
 
330
    toRoman(number, &number_string, gFalse);
 
331
    break;
 
332
  case Interval::UppercaseRoman:
 
333
    toRoman(number, &number_string, gTrue);
 
334
    break;
 
335
  case Interval::UppercaseLatin:
 
336
  case Interval::LowercaseLatin:
 
337
    number = 0;
 
338
    break;
 
339
  case Interval::None:
 
340
    break;
 
341
  }
 
342
 
 
343
  label->clear();
 
344
  label->append(interval->prefix);
 
345
  if (label->hasUnicodeMarker()) {
 
346
      int i, len;
 
347
      char ucs2_char[2];
 
348
 
 
349
      /* Convert the ascii number string to ucs2 and append. */
 
350
      len = number_string.getLength ();
 
351
      ucs2_char[0] = 0;
 
352
      for (i = 0; i < len; ++i) {
 
353
          ucs2_char[1] = number_string.getChar(i);
 
354
          label->append(ucs2_char, 2);
 
355
      }
 
356
      ucs2_char[1] = 0;
 
357
      label->append(ucs2_char, 2);
 
358
  } else {
 
359
      label->append(&number_string);
 
360
  }
 
361
 
 
362
  return gTrue;
 
363
}
 
364
 
 
365
#ifdef TEST
 
366
int main(int argc, char *argv[])
 
367
{
 
368
  {
 
369
    GooString str;
 
370
    toRoman(177, &str, gFalse);
 
371
    assert (str.cmp("clxxvii") == 0);
 
372
  }
 
373
 
 
374
  {
 
375
    GooString roman("clxxvii");
 
376
    assert (fromRoman(roman.getCString()) == 177);
 
377
  }
 
378
 
 
379
  {
 
380
    GooString str;
 
381
    toLatin(54, &str, gFalse);
 
382
    assert (str.cmp("bbb") == 0);
 
383
  }
 
384
 
 
385
  {
 
386
    GooString latin("ddd");
 
387
    assert (fromLatin(latin.getCString()) == 56);
 
388
  }
 
389
}
 
390
#endif