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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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