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

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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