source: trunk/poppler/mypoppler/poppler/CharCodeToUnicode.cc @ 277

Last change on this file since 277 was 277, checked in by rbri, 11 years ago

PDF plugin: Poppler library updated to version 0.12.3

File size: 14.8 KB
Line 
1//========================================================================
2//
3// CharCodeToUnicode.cc
4//
5// Copyright 2001-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2006, 2008, 2009 Albert Astals Cid <aacid@kde.org>
17// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
18// Copyright (C) 2007 Koji Otani <sho@bbr.jp>
19// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
20// Copyright (C) 2008 Vasile Gaburici <gaburici@cs.umd.edu>
21//
22// To see a description of the changes please see the Changelog file that
23// came with your tarball or type make ChangeLog if you are building from git
24//
25//========================================================================
26
27#include <config.h>
28
29#ifdef USE_GCC_PRAGMAS
30#pragma implementation
31#endif
32
33#include <stdio.h>
34#include <string.h>
35#include "goo/gmem.h"
36#include "goo/gfile.h"
37#include "goo/GooString.h"
38#include "Error.h"
39#include "GlobalParams.h"
40#include "PSTokenizer.h"
41#include "CharCodeToUnicode.h"
42
43//------------------------------------------------------------------------
44
45struct CharCodeToUnicodeString {
46  CharCode c;
47  Unicode *u;
48  int len;
49};
50
51//------------------------------------------------------------------------
52
53static int getCharFromString(void *data) {
54  char *p;
55  int c;
56
57  p = *(char **)data;
58  if (*p) {
59    c = *p++;
60    *(char **)data = p;
61  } else {
62    c = EOF;
63  }
64  return c;
65}
66
67static int getCharFromFile(void *data) {
68  return fgetc((FILE *)data);
69}
70
71//------------------------------------------------------------------------
72
73CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GooString *fileName,
74                                                        GooString *collection) {
75  FILE *f;
76  Unicode *mapA;
77  CharCode size, mapLenA;
78  char buf[64];
79  Unicode u;
80  CharCodeToUnicode *ctu;
81
82  if (!(f = fopen(fileName->getCString(), "r"))) {
83    error(-1, "Couldn't open cidToUnicode file '%s'",
84          fileName->getCString());
85    return NULL;
86  }
87
88  size = 32768;
89  mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
90  mapLenA = 0;
91
92  while (getLine(buf, sizeof(buf), f)) {
93    if (mapLenA == size) {
94      size *= 2;
95      mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
96    }
97    if (sscanf(buf, "%x", &u) == 1) {
98      mapA[mapLenA] = u;
99    } else {
100      error(-1, "Bad line (%d) in cidToUnicode file '%s'",
101            (int)(mapLenA + 1), fileName->getCString());
102      mapA[mapLenA] = 0;
103    }
104    ++mapLenA;
105  }
106  fclose(f);
107
108  ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue,
109                              NULL, 0, 0);
110  gfree(mapA);
111  return ctu;
112}
113
114CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
115                                                    GooString *fileName) {
116  FILE *f;
117  Unicode *mapA;
118  CharCodeToUnicodeString *sMapA;
119  CharCode size, oldSize, len, sMapSizeA, sMapLenA;
120  char buf[256];
121  char *tok;
122  Unicode u0;
123  int uBufSize = 8;
124  Unicode *uBuf = (Unicode *)gmallocn(uBufSize, sizeof(Unicode));
125  CharCodeToUnicode *ctu;
126  int line, n, i;
127
128  if (!(f = fopen(fileName->getCString(), "r"))) {
129    gfree(uBuf);
130    error(-1, "Couldn't open unicodeToUnicode file '%s'",
131          fileName->getCString());
132    return NULL;
133  }
134
135  size = 4096;
136  mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
137  memset(mapA, 0, size * sizeof(Unicode));
138  len = 0;
139  sMapA = NULL;
140  sMapSizeA = sMapLenA = 0;
141
142  line = 0;
143  while (getLine(buf, sizeof(buf), f)) {
144    ++line;
145    if (!(tok = strtok(buf, " \t\r\n")) ||
146        sscanf(tok, "%x", &u0) != 1) {
147      error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
148            line, fileName->getCString());
149      continue;
150    }
151    n = 0;
152    while ((tok = strtok(NULL, " \t\r\n"))) {
153      if (n >= uBufSize)
154      {
155        uBufSize += 8;
156        uBuf = (Unicode *)greallocn(uBuf, uBufSize, sizeof(Unicode));
157      }
158      if (sscanf(tok, "%x", &uBuf[n]) != 1) {
159        error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
160              line, fileName->getCString());
161        break;
162      }
163      ++n;
164    }
165    if (n < 1) {
166      error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
167            line, fileName->getCString());
168      continue;
169    }
170    if (u0 >= size) {
171      oldSize = size;
172      while (u0 >= size) {
173        size *= 2;
174      }
175      mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
176      memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
177    }
178    if (n == 1) {
179      mapA[u0] = uBuf[0];
180    } else {
181      mapA[u0] = 0;
182      if (sMapLenA == sMapSizeA) {
183        sMapSizeA += 16;
184        sMapA = (CharCodeToUnicodeString *)
185                  greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
186      }
187      sMapA[sMapLenA].c = u0;
188      sMapA[sMapLenA].u = (Unicode*)gmallocn(n, sizeof(Unicode));
189      for (i = 0; i < n; ++i) {
190        sMapA[sMapLenA].u[i] = uBuf[i];
191      }
192      sMapA[sMapLenA].len = n;
193      ++sMapLenA;
194    }
195    if (u0 >= len) {
196      len = u0 + 1;
197    }
198  }
199  fclose(f);
200
201  ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
202                              sMapA, sMapLenA, sMapSizeA);
203  gfree(mapA);
204  gfree(uBuf);
205  return ctu;
206}
207
208CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
209  return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
210}
211
212CharCodeToUnicode *CharCodeToUnicode::parseCMap(GooString *buf, int nBits) {
213  CharCodeToUnicode *ctu;
214  char *p;
215
216  ctu = new CharCodeToUnicode(NULL);
217  p = buf->getCString();
218  ctu->parseCMap1(&getCharFromString, &p, nBits);
219  return ctu;
220}
221
222CharCodeToUnicode *CharCodeToUnicode::parseCMapFromFile(GooString *fileName,
223  int nBits) {
224  CharCodeToUnicode *ctu;
225  FILE *f;
226
227  ctu = new CharCodeToUnicode(NULL);
228  if ((f = globalParams->findToUnicodeFile(fileName))) {
229    ctu->parseCMap1(&getCharFromFile, f, nBits);
230    fclose(f);
231  } else {
232    error(-1, "Couldn't find ToUnicode CMap file for '%s'",
233          fileName->getCString());
234  }
235  return ctu;
236}
237
238void CharCodeToUnicode::mergeCMap(GooString *buf, int nBits) {
239  char *p;
240
241  p = buf->getCString();
242  parseCMap1(&getCharFromString, &p, nBits);
243}
244
245void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
246                                   int nBits) {
247  PSTokenizer *pst;
248  char tok1[256], tok2[256], tok3[256];
249  int nDigits, n1, n2, n3;
250  CharCode i;
251  CharCode code1, code2;
252  GooString *name;
253  FILE *f;
254
255  nDigits = nBits / 4;
256  pst = new PSTokenizer(getCharFunc, data);
257  pst->getToken(tok1, sizeof(tok1), &n1);
258  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
259    if (!strcmp(tok2, "usecmap")) {
260      if (tok1[0] == '/') {
261        name = new GooString(tok1 + 1);
262        if ((f = globalParams->findToUnicodeFile(name))) {
263          parseCMap1(&getCharFromFile, f, nBits);
264          fclose(f);
265        } else {
266          error(-1, "Couldn't find ToUnicode CMap file for '%s'",
267                name->getCString());
268        }
269        delete name;
270      }
271      pst->getToken(tok1, sizeof(tok1), &n1);
272    } else if (!strcmp(tok2, "beginbfchar")) {
273      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
274        if (!strcmp(tok1, "endbfchar")) {
275          break;
276        }
277        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
278            !strcmp(tok2, "endbfchar")) {
279          error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
280          break;
281        }
282        if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
283              tok2[0] == '<' && tok2[n2 - 1] == '>')) {
284          if (!(n1 == 4 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && tok1[1] == '0' && tok1[2] == '0' &&
285                tok2[0] == '<' && tok2[n2 - 1] == '>')) {
286            error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
287            continue;
288          }
289        }
290        tok1[n1 - 1] = tok2[n2 - 1] = '\0';
291        if (sscanf(tok1 + 1, "%x", &code1) != 1) {
292          error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
293          continue;
294        }
295        addMapping(code1, tok2 + 1, n2 - 2, 0);
296      }
297      pst->getToken(tok1, sizeof(tok1), &n1);
298    } else if (!strcmp(tok2, "beginbfrange")) {
299      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
300        if (!strcmp(tok1, "endbfrange")) {
301          break;
302        }
303        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
304            !strcmp(tok2, "endbfrange") ||
305            !pst->getToken(tok3, sizeof(tok3), &n3) ||
306            !strcmp(tok3, "endbfrange")) {
307          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
308          break;
309        }
310        if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
311              n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
312          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
313          continue;
314        }
315        tok1[n1 - 1] = tok2[n2 - 1] = '\0';
316        if (sscanf(tok1 + 1, "%x", &code1) != 1 ||
317            sscanf(tok2 + 1, "%x", &code2) != 1) {
318          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
319          continue;
320        }
321        if (!strcmp(tok3, "[")) {
322          i = 0;
323          while (pst->getToken(tok1, sizeof(tok1), &n1) &&
324                 code1 + i <= code2) {
325            if (!strcmp(tok1, "]")) {
326              break;
327            }
328            if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
329              tok1[n1 - 1] = '\0';
330              addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
331            } else {
332              error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
333            }
334            ++i;
335          }
336        } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
337          tok3[n3 - 1] = '\0';
338          for (i = 0; code1 <= code2; ++code1, ++i) {
339            addMapping(code1, tok3 + 1, n3 - 2, i);
340          }
341
342        } else {
343          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
344        }
345      }
346      pst->getToken(tok1, sizeof(tok1), &n1);
347    } else {
348      strcpy(tok1, tok2);
349    }
350  }
351  delete pst;
352}
353
354void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
355                                   int offset) {
356  CharCode oldLen, i;
357  Unicode u;
358  char uHex[5];
359  int j;
360
361  if (code >= mapLen) {
362    oldLen = mapLen;
363    mapLen = (code + 256) & ~255;
364    map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
365    for (i = oldLen; i < mapLen; ++i) {
366      map[i] = 0;
367    }
368  }
369  if (n <= 4) {
370    if (sscanf(uStr, "%x", &u) != 1) {
371      error(-1, "Illegal entry in ToUnicode CMap");
372      return;
373    }
374    map[code] = u + offset;
375  } else {
376    if (sMapLen >= sMapSize) {
377      sMapSize = sMapSize + 16;
378      sMap = (CharCodeToUnicodeString *)
379               greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
380    }
381    map[code] = 0;
382    sMap[sMapLen].c = code;
383    sMap[sMapLen].len = n / 4;
384    sMap[sMapLen].u = (Unicode*)gmallocn(sMap[sMapLen].len, sizeof(Unicode));
385    for (j = 0; j < sMap[sMapLen].len; ++j) {
386      strncpy(uHex, uStr + j*4, 4);
387      uHex[4] = '\0';
388      if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
389        error(-1, "Illegal entry in ToUnicode CMap");
390      }
391    }
392    sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
393    ++sMapLen;
394  }
395}
396
397CharCodeToUnicode::CharCodeToUnicode(GooString *tagA) {
398  CharCode i;
399
400  tag = tagA;
401  mapLen = 256;
402  map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
403  for (i = 0; i < mapLen; ++i) {
404    map[i] = 0;
405  }
406  sMap = NULL;
407  sMapLen = sMapSize = 0;
408  refCnt = 1;
409#if MULTITHREADED
410  gInitMutex(&mutex);
411#endif
412}
413
414CharCodeToUnicode::CharCodeToUnicode(GooString *tagA, Unicode *mapA,
415                                     CharCode mapLenA, GBool copyMap,
416                                     CharCodeToUnicodeString *sMapA,
417                                     int sMapLenA, int sMapSizeA) {
418  tag = tagA;
419  mapLen = mapLenA;
420  if (copyMap) {
421    map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
422    memcpy(map, mapA, mapLen * sizeof(Unicode));
423  } else {
424    map = mapA;
425  }
426  sMap = sMapA;
427  sMapLen = sMapLenA;
428  sMapSize = sMapSizeA;
429  refCnt = 1;
430#if MULTITHREADED
431  gInitMutex(&mutex);
432#endif
433}
434
435CharCodeToUnicode::~CharCodeToUnicode() {
436  if (tag) {
437    delete tag;
438  }
439  gfree(map);
440  if (sMap) {
441    for (int i = 0; i < sMapLen; ++i) gfree(sMap[i].u);
442    gfree(sMap);
443  }
444#if MULTITHREADED
445  gDestroyMutex(&mutex);
446#endif
447}
448
449void CharCodeToUnicode::incRefCnt() {
450#if MULTITHREADED
451  gLockMutex(&mutex);
452#endif
453  ++refCnt;
454#if MULTITHREADED
455  gUnlockMutex(&mutex);
456#endif
457}
458
459void CharCodeToUnicode::decRefCnt() {
460  GBool done;
461
462#if MULTITHREADED
463  gLockMutex(&mutex);
464#endif
465  done = --refCnt == 0;
466#if MULTITHREADED
467  gUnlockMutex(&mutex);
468#endif
469  if (done) {
470    delete this;
471  }
472}
473
474GBool CharCodeToUnicode::match(GooString *tagA) {
475  return tag && !tag->cmp(tagA);
476}
477
478void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
479  int i, j;
480
481  if (len == 1) {
482    map[c] = u[0];
483  } else {
484    for (i = 0; i < sMapLen; ++i) {
485      if (sMap[i].c == c) {
486        gfree(sMap[i].u);
487        break;
488      }
489    }
490    if (i == sMapLen) {
491      if (sMapLen == sMapSize) {
492        sMapSize += 8;
493        sMap = (CharCodeToUnicodeString *)
494                 greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
495      }
496      ++sMapLen;
497    }
498    map[c] = 0;
499    sMap[i].c = c;
500    sMap[i].len = len;
501    sMap[i].u = (Unicode*)gmallocn(len, sizeof(Unicode));
502    for (j = 0; j < len; ++j) {
503      sMap[i].u[j] = u[j];
504    }
505  }
506}
507
508int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode **u) {
509  int i;
510
511  if (c >= mapLen) {
512    return 0;
513  }
514  if (map[c]) {
515    *u = &map[c];
516    return 1;
517  }
518  for (i = sMapLen - 1; i >= 0; --i) { // in reverse so CMap takes precedence
519    if (sMap[i].c == c) {
520      *u = sMap[i].u;
521      return sMap[i].len;
522    }
523  }
524  return 0;
525}
526
527int CharCodeToUnicode::mapToCharCode(Unicode* u, CharCode *c, int usize) {
528  //look for charcode in map
529  if (usize == 1) {
530    for (CharCode i=0; i<mapLen; i++) {
531      if (map[i] == *u) {
532        *c = i;
533        return 1;
534      }
535    }
536    *c = 'x';
537  } else {
538    int i, j;
539    //for each entry in the sMap
540    for (i=0; i<sMapLen; i++) {
541      //if the entry's unicode length isn't the same are usize, the strings
542      // are obviously differents
543      if (sMap[i].len != usize) continue;
544      //compare the string char by char
545      for (j=0; j<sMap[i].len; j++) {
546        if (sMap[i].u[j] != u[j]) {
547          continue;
548        }
549      }
550
551      //we have the same strings
552      if (j==sMap[i].len) { 
553        *c = sMap[i].c;
554        return 1;
555      }
556    }
557  }
558  return 0;
559}
560
561//------------------------------------------------------------------------
562
563CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
564  int i;
565
566  size = sizeA;
567  cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
568  for (i = 0; i < size; ++i) {
569    cache[i] = NULL;
570  }
571}
572
573CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
574  int i;
575
576  for (i = 0; i < size; ++i) {
577    if (cache[i]) {
578      cache[i]->decRefCnt();
579    }
580  }
581  gfree(cache);
582}
583
584CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GooString *tag) {
585  CharCodeToUnicode *ctu;
586  int i, j;
587
588  if (cache[0] && cache[0]->match(tag)) {
589    cache[0]->incRefCnt();
590    return cache[0];
591  }
592  for (i = 1; i < size; ++i) {
593    if (cache[i] && cache[i]->match(tag)) {
594      ctu = cache[i];
595      for (j = i; j >= 1; --j) {
596        cache[j] = cache[j - 1];
597      }
598      cache[0] = ctu;
599      ctu->incRefCnt();
600      return ctu;
601    }
602  }
603  return NULL;
604}
605
606void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
607  int i;
608
609  if (cache[size - 1]) {
610    cache[size - 1]->decRefCnt();
611  }
612  for (i = size - 1; i >= 1; --i) {
613    cache[i] = cache[i - 1];
614  }
615  cache[0] = ctu;
616  ctu->incRefCnt();
617}
Note: See TracBrowser for help on using the repository browser.