source: trunk/poppler/mypoppler/poppler/CharCodeToUnicode.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: 14.6 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 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    error(-1, "Couldn't open unicodeToUnicode file '%s'",
130          fileName->getCString());
131    return NULL;
132  }
133
134  size = 4096;
135  mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
136  memset(mapA, 0, size * sizeof(Unicode));
137  len = 0;
138  sMapA = NULL;
139  sMapSizeA = sMapLenA = 0;
140
141  line = 0;
142  while (getLine(buf, sizeof(buf), f)) {
143    ++line;
144    if (!(tok = strtok(buf, " \t\r\n")) ||
145        sscanf(tok, "%x", &u0) != 1) {
146      error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
147            line, fileName->getCString());
148      continue;
149    }
150    n = 0;
151    while ((tok = strtok(NULL, " \t\r\n"))) {
152      if (n >= uBufSize)
153      {
154        uBufSize += 8;
155        uBuf = (Unicode *)greallocn(uBuf, uBufSize, sizeof(Unicode));
156      }
157      if (sscanf(tok, "%x", &uBuf[n]) != 1) {
158        error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
159              line, fileName->getCString());
160        break;
161      }
162      ++n;
163    }
164    if (n < 1) {
165      error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
166            line, fileName->getCString());
167      continue;
168    }
169    if (u0 >= size) {
170      oldSize = size;
171      while (u0 >= size) {
172        size *= 2;
173      }
174      mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
175      memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
176    }
177    if (n == 1) {
178      mapA[u0] = uBuf[0];
179    } else {
180      mapA[u0] = 0;
181      if (sMapLenA == sMapSizeA) {
182        sMapSizeA += 16;
183        sMapA = (CharCodeToUnicodeString *)
184                  greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
185      }
186      sMapA[sMapLenA].c = u0;
187      sMapA[sMapLenA].u = (Unicode*)gmallocn(n, sizeof(Unicode));
188      for (i = 0; i < n; ++i) {
189        sMapA[sMapLenA].u[i] = uBuf[i];
190      }
191      sMapA[sMapLenA].len = n;
192      ++sMapLenA;
193    }
194    if (u0 >= len) {
195      len = u0 + 1;
196    }
197  }
198  fclose(f);
199
200  ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
201                              sMapA, sMapLenA, sMapSizeA);
202  gfree(mapA);
203  gfree(uBuf);
204  return ctu;
205}
206
207CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
208  return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
209}
210
211CharCodeToUnicode *CharCodeToUnicode::parseCMap(GooString *buf, int nBits) {
212  CharCodeToUnicode *ctu;
213  char *p;
214
215  ctu = new CharCodeToUnicode(NULL);
216  p = buf->getCString();
217  ctu->parseCMap1(&getCharFromString, &p, nBits);
218  return ctu;
219}
220
221CharCodeToUnicode *CharCodeToUnicode::parseCMapFromFile(GooString *fileName,
222  int nBits) {
223  CharCodeToUnicode *ctu;
224  FILE *f;
225
226  ctu = new CharCodeToUnicode(NULL);
227  if ((f = globalParams->findToUnicodeFile(fileName))) {
228    ctu->parseCMap1(&getCharFromFile, f, nBits);
229    fclose(f);
230  } else {
231    error(-1, "Couldn't find ToUnicode CMap file for '%s'",
232          fileName->getCString());
233  }
234  return ctu;
235}
236
237void CharCodeToUnicode::mergeCMap(GooString *buf, int nBits) {
238  char *p;
239
240  p = buf->getCString();
241  parseCMap1(&getCharFromString, &p, nBits);
242}
243
244void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
245                                   int nBits) {
246  PSTokenizer *pst;
247  char tok1[256], tok2[256], tok3[256];
248  int nDigits, n1, n2, n3;
249  CharCode i;
250  CharCode code1, code2;
251  GooString *name;
252  FILE *f;
253
254  nDigits = nBits / 4;
255  pst = new PSTokenizer(getCharFunc, data);
256  pst->getToken(tok1, sizeof(tok1), &n1);
257  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
258    if (!strcmp(tok2, "usecmap")) {
259      if (tok1[0] == '/') {
260        name = new GooString(tok1 + 1);
261        if ((f = globalParams->findToUnicodeFile(name))) {
262          parseCMap1(&getCharFromFile, f, nBits);
263          fclose(f);
264        } else {
265          error(-1, "Couldn't find ToUnicode CMap file for '%s'",
266                name->getCString());
267        }
268        delete name;
269      }
270      pst->getToken(tok1, sizeof(tok1), &n1);
271    } else if (!strcmp(tok2, "beginbfchar")) {
272      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
273        if (!strcmp(tok1, "endbfchar")) {
274          break;
275        }
276        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
277            !strcmp(tok2, "endbfchar")) {
278          error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
279          break;
280        }
281        if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
282              tok2[0] == '<' && tok2[n2 - 1] == '>')) {
283          error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
284          continue;
285        }
286        tok1[n1 - 1] = tok2[n2 - 1] = '\0';
287        if (sscanf(tok1 + 1, "%x", &code1) != 1) {
288          error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
289          continue;
290        }
291        addMapping(code1, tok2 + 1, n2 - 2, 0);
292      }
293      pst->getToken(tok1, sizeof(tok1), &n1);
294    } else if (!strcmp(tok2, "beginbfrange")) {
295      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
296        if (!strcmp(tok1, "endbfrange")) {
297          break;
298        }
299        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
300            !strcmp(tok2, "endbfrange") ||
301            !pst->getToken(tok3, sizeof(tok3), &n3) ||
302            !strcmp(tok3, "endbfrange")) {
303          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
304          break;
305        }
306        if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
307              n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
308          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
309          continue;
310        }
311        tok1[n1 - 1] = tok2[n2 - 1] = '\0';
312        if (sscanf(tok1 + 1, "%x", &code1) != 1 ||
313            sscanf(tok2 + 1, "%x", &code2) != 1) {
314          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
315          continue;
316        }
317        if (!strcmp(tok3, "[")) {
318          i = 0;
319          while (pst->getToken(tok1, sizeof(tok1), &n1) &&
320                 code1 + i <= code2) {
321            if (!strcmp(tok1, "]")) {
322              break;
323            }
324            if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
325              tok1[n1 - 1] = '\0';
326              addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
327            } else {
328              error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
329            }
330            ++i;
331          }
332        } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
333          tok3[n3 - 1] = '\0';
334          for (i = 0; code1 <= code2; ++code1, ++i) {
335            addMapping(code1, tok3 + 1, n3 - 2, i);
336          }
337
338        } else {
339          error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
340        }
341      }
342      pst->getToken(tok1, sizeof(tok1), &n1);
343    } else {
344      strcpy(tok1, tok2);
345    }
346  }
347  delete pst;
348}
349
350void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
351                                   int offset) {
352  CharCode oldLen, i;
353  Unicode u;
354  char uHex[5];
355  int j;
356
357  if (code >= mapLen) {
358    oldLen = mapLen;
359    mapLen = (code + 256) & ~255;
360    map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
361    for (i = oldLen; i < mapLen; ++i) {
362      map[i] = 0;
363    }
364  }
365  if (n <= 4) {
366    if (sscanf(uStr, "%x", &u) != 1) {
367      error(-1, "Illegal entry in ToUnicode CMap");
368      return;
369    }
370    map[code] = u + offset;
371  } else {
372    if (sMapLen >= sMapSize) {
373      sMapSize = sMapSize + 16;
374      sMap = (CharCodeToUnicodeString *)
375               greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
376    }
377    map[code] = 0;
378    sMap[sMapLen].c = code;
379    sMap[sMapLen].len = n / 4;
380    sMap[sMapLen].u = (Unicode*)gmallocn(sMap[sMapLen].len, sizeof(Unicode));
381    for (j = 0; j < sMap[sMapLen].len; ++j) {
382      strncpy(uHex, uStr + j*4, 4);
383      uHex[4] = '\0';
384      if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
385        error(-1, "Illegal entry in ToUnicode CMap");
386      }
387    }
388    sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
389    ++sMapLen;
390  }
391}
392
393CharCodeToUnicode::CharCodeToUnicode(GooString *tagA) {
394  CharCode i;
395
396  tag = tagA;
397  mapLen = 256;
398  map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
399  for (i = 0; i < mapLen; ++i) {
400    map[i] = 0;
401  }
402  sMap = NULL;
403  sMapLen = sMapSize = 0;
404  refCnt = 1;
405#if MULTITHREADED
406  gInitMutex(&mutex);
407#endif
408}
409
410CharCodeToUnicode::CharCodeToUnicode(GooString *tagA, Unicode *mapA,
411                                     CharCode mapLenA, GBool copyMap,
412                                     CharCodeToUnicodeString *sMapA,
413                                     int sMapLenA, int sMapSizeA) {
414  tag = tagA;
415  mapLen = mapLenA;
416  if (copyMap) {
417    map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
418    memcpy(map, mapA, mapLen * sizeof(Unicode));
419  } else {
420    map = mapA;
421  }
422  sMap = sMapA;
423  sMapLen = sMapLenA;
424  sMapSize = sMapSizeA;
425  refCnt = 1;
426#if MULTITHREADED
427  gInitMutex(&mutex);
428#endif
429}
430
431CharCodeToUnicode::~CharCodeToUnicode() {
432  if (tag) {
433    delete tag;
434  }
435  gfree(map);
436  if (sMap) {
437    for (int i = 0; i < sMapLen; ++i) gfree(sMap[i].u);
438    gfree(sMap);
439  }
440#if MULTITHREADED
441  gDestroyMutex(&mutex);
442#endif
443}
444
445void CharCodeToUnicode::incRefCnt() {
446#if MULTITHREADED
447  gLockMutex(&mutex);
448#endif
449  ++refCnt;
450#if MULTITHREADED
451  gUnlockMutex(&mutex);
452#endif
453}
454
455void CharCodeToUnicode::decRefCnt() {
456  GBool done;
457
458#if MULTITHREADED
459  gLockMutex(&mutex);
460#endif
461  done = --refCnt == 0;
462#if MULTITHREADED
463  gUnlockMutex(&mutex);
464#endif
465  if (done) {
466    delete this;
467  }
468}
469
470GBool CharCodeToUnicode::match(GooString *tagA) {
471  return tag && !tag->cmp(tagA);
472}
473
474void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
475  int i, j;
476
477  if (len == 1) {
478    map[c] = u[0];
479  } else {
480    for (i = 0; i < sMapLen; ++i) {
481      if (sMap[i].c == c) {
482        gfree(sMap[i].u);
483        break;
484      }
485    }
486    if (i == sMapLen) {
487      if (sMapLen == sMapSize) {
488        sMapSize += 8;
489        sMap = (CharCodeToUnicodeString *)
490                 greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
491      }
492      ++sMapLen;
493    }
494    map[c] = 0;
495    sMap[i].c = c;
496    sMap[i].len = len;
497    sMap[i].u = (Unicode*)gmallocn(len, sizeof(Unicode));
498    for (j = 0; j < len; ++j) {
499      sMap[i].u[j] = u[j];
500    }
501  }
502}
503
504int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode **u) {
505  int i;
506
507  if (c >= mapLen) {
508    return 0;
509  }
510  if (map[c]) {
511    *u = &map[c];
512    return 1;
513  }
514  for (i = sMapLen - 1; i >= 0; --i) { // in reverse so CMap takes precedence
515    if (sMap[i].c == c) {
516      *u = sMap[i].u;
517      return sMap[i].len;
518    }
519  }
520  return 0;
521}
522
523int CharCodeToUnicode::mapToCharCode(Unicode* u, CharCode *c, int usize) {
524  //look for charcode in map
525  if (usize == 1) {
526    for (CharCode i=0; i<mapLen; i++) {
527      if (map[i] == *u) {
528        *c = i;
529        return 1;
530      }
531    }
532    *c = 'x';
533  } else {
534    int i, j;
535    //for each entry in the sMap
536    for (i=0; i<sMapLen; i++) {
537      //if the entry's unicode length isn't the same are usize, the strings
538      // are obviously differents
539      if (sMap[i].len != usize) continue;
540      //compare the string char by char
541      for (j=0; j<sMap[i].len; j++) {
542        if (sMap[i].u[j] != u[j]) {
543          continue;
544        }
545      }
546
547      //we have the same strings
548      if (j==sMap[i].len) { 
549        *c = sMap[i].c;
550        return 1;
551      }
552    }
553  }
554  return 0;
555}
556
557//------------------------------------------------------------------------
558
559CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
560  int i;
561
562  size = sizeA;
563  cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
564  for (i = 0; i < size; ++i) {
565    cache[i] = NULL;
566  }
567}
568
569CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
570  int i;
571
572  for (i = 0; i < size; ++i) {
573    if (cache[i]) {
574      cache[i]->decRefCnt();
575    }
576  }
577  gfree(cache);
578}
579
580CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GooString *tag) {
581  CharCodeToUnicode *ctu;
582  int i, j;
583
584  if (cache[0] && cache[0]->match(tag)) {
585    cache[0]->incRefCnt();
586    return cache[0];
587  }
588  for (i = 1; i < size; ++i) {
589    if (cache[i] && cache[i]->match(tag)) {
590      ctu = cache[i];
591      for (j = i; j >= 1; --j) {
592        cache[j] = cache[j - 1];
593      }
594      cache[0] = ctu;
595      ctu->incRefCnt();
596      return ctu;
597    }
598  }
599  return NULL;
600}
601
602void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
603  int i;
604
605  if (cache[size - 1]) {
606    cache[size - 1]->decRefCnt();
607  }
608  for (i = size - 1; i >= 1; --i) {
609    cache[i] = cache[i - 1];
610  }
611  cache[0] = ctu;
612  ctu->incRefCnt();
613}
Note: See TracBrowser for help on using the repository browser.