root/middleware-offline/trunk/_src/eidmw/pteid-poppler/poppler/CMap.cc @ 226

Revision 226, 14.4 KB (checked in by vsilva, 8 years ago)

Improve PDF native Signature

Line 
1//========================================================================
2//
3// CMap.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) 2008 Koji Otani <sho@bbr.jp>
17// Copyright (C) 2008, 2009 Albert Astals Cid <aacid@kde.org>
18//
19// To see a description of the changes please see the Changelog file that
20// came with your tarball or type make ChangeLog if you are building from git
21//
22//========================================================================
23
24#include <config.h>
25
26#ifdef USE_GCC_PRAGMAS
27#pragma implementation
28#endif
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <ctype.h>
34#include "goo/gmem.h"
35#include "goo/gfile.h"
36#include "goo/GooString.h"
37#include "Error.h"
38#include "GlobalParams.h"
39#include "PSTokenizer.h"
40#include "CMap.h"
41#include "Object.h"
42
43//------------------------------------------------------------------------
44
45struct CMapVectorEntry {
46  GBool isVector;
47  union {
48    CMapVectorEntry *vector;
49    CID cid;
50  };
51};
52
53//------------------------------------------------------------------------
54
55static int getCharFromFile(void *data) {
56  return fgetc((FILE *)data);
57}
58
59static int getCharFromStream(void *data) {
60  return ((Stream *)data)->getChar();
61}
62
63//------------------------------------------------------------------------
64
65CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Object *obj) {
66  CMap *cMap;
67  GooString *cMapNameA;
68
69  if (obj->isName()) {
70    cMapNameA = new GooString(obj->getName());
71    if (!(cMap = globalParams->getCMap(collectionA, cMapNameA))) {
72      error(errSyntaxError, -1,
73            "Unknown CMap '{0:t}' for character collection '{1:t}'",
74            cMapNameA, collectionA);
75    }
76    delete cMapNameA;
77  } else if (obj->isStream()) {
78    if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream()))) {
79      error(errSyntaxError, -1, "Invalid CMap in Type 0 font");
80    }
81  } else {
82    error(errSyntaxError, -1, "Invalid Encoding in Type 0 font");
83    return NULL;
84  }
85  return cMap;
86}
87
88CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
89                  GooString *cMapNameA) {
90  FILE *f;
91  CMap *cMap;
92
93  if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
94
95    // Check for an identity CMap.
96    if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
97      return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
98    }
99    if (!cMapNameA->cmp("Identity-V")) {
100      return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
101    }
102
103    error(errSyntaxError, -1,
104          "Couldn't find '{0:t}' CMap file for '{1:t}' collection",
105          cMapNameA, collectionA);
106    return NULL;
107  }
108
109  cMap = new CMap(collectionA->copy(), cMapNameA->copy());
110  cMap->parse2(cache, &getCharFromFile, f);
111
112  fclose(f);
113
114  return cMap;
115}
116
117CMap *CMap::parse(CMapCache *cache, GooString *collectionA, Stream *str) {
118  Object obj1;
119  CMap *cMap;
120
121  cMap = new CMap(collectionA->copy(), NULL);
122
123  if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) {
124    cMap->useCMap(cache, &obj1);
125  }
126  obj1.free();
127
128  str->reset();
129  cMap->parse2(cache, &getCharFromStream, str);
130  str->close();
131  return cMap;
132}
133
134CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
135                  GooString *cMapNameA, Stream *stream) {
136  FILE *f = NULL;
137  CMap *cmap;
138  PSTokenizer *pst;
139  char tok1[256], tok2[256], tok3[256];
140  int n1, n2, n3;
141  Guint start, end, code;
142
143  if (stream) {
144    stream->reset();
145    pst = new PSTokenizer(&getCharFromStream, stream);
146  } else {
147    if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
148
149      // Check for an identity CMap.
150      if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
151        return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
152      }
153      if (!cMapNameA->cmp("Identity-V")) {
154        return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
155      }
156
157      error(errSyntaxError, -1, "Couldn't find '{0:t}' CMap file for '{1:t}' collection",
158            cMapNameA, collectionA);
159      return NULL;
160    }
161    pst = new PSTokenizer(&getCharFromFile, f);
162  }
163
164  cmap = new CMap(collectionA->copy(), cMapNameA->copy());
165
166  pst->getToken(tok1, sizeof(tok1), &n1);
167  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
168    if (!strcmp(tok2, "usecmap")) {
169      if (tok1[0] == '/') {
170        cmap->useCMap(cache, tok1 + 1);
171      }
172      pst->getToken(tok1, sizeof(tok1), &n1);
173    } else if (!strcmp(tok1, "/WMode")) {
174      cmap->wMode = atoi(tok2);
175      pst->getToken(tok1, sizeof(tok1), &n1);
176    } else if (!strcmp(tok2, "begincidchar")) {
177      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
178        if (!strcmp(tok1, "endcidchar")) {
179          break;
180        }
181        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
182            !strcmp(tok2, "endcidchar")) {
183          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
184          break;
185        }
186        if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
187              n1 >= 4 && (n1 & 1) == 0)) {
188          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
189          continue;
190        }
191        tok1[n1 - 1] = '\0';
192        if (sscanf(tok1 + 1, "%x", &code) != 1) {
193          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
194          continue;
195        }
196        n1 = (n1 - 2) / 2;
197        cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
198      }
199      pst->getToken(tok1, sizeof(tok1), &n1);
200    } else if (!strcmp(tok2, "begincidrange")) {
201      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
202        if (!strcmp(tok1, "endcidrange")) {
203          break;
204        }
205        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
206            !strcmp(tok2, "endcidrange") ||
207            !pst->getToken(tok3, sizeof(tok3), &n3) ||
208            !strcmp(tok3, "endcidrange")) {
209          error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap");
210          break;
211        }
212        if (tok1[0] == '<' && tok2[0] == '<' &&
213            n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
214          tok1[n1 - 1] = tok2[n1 - 1] = '\0';
215          sscanf(tok1 + 1, "%x", &start);
216          sscanf(tok2 + 1, "%x", &end);
217          n1 = (n1 - 2) / 2;
218          cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
219        }
220      }
221      pst->getToken(tok1, sizeof(tok1), &n1);
222    } else {
223      strcpy(tok1, tok2);
224    }
225  }
226  delete pst;
227
228  if (f) {
229    fclose(f);
230  }
231
232  return cmap;
233}
234
235void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) {
236  PSTokenizer *pst;
237  char tok1[256], tok2[256], tok3[256];
238  int n1, n2, n3;
239  Guint start, end, code;
240
241  pst = new PSTokenizer(getCharFunc, data);
242  pst->getToken(tok1, sizeof(tok1), &n1);
243  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
244    if (!strcmp(tok2, "usecmap")) {
245      if (tok1[0] == '/') {
246        useCMap(cache, tok1 + 1);
247      }
248      pst->getToken(tok1, sizeof(tok1), &n1);
249    } else if (!strcmp(tok1, "/WMode")) {
250      wMode = atoi(tok2);
251      pst->getToken(tok1, sizeof(tok1), &n1);
252    } else if (!strcmp(tok2, "begincidchar")) {
253      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
254        if (!strcmp(tok1, "endcidchar")) {
255          break;
256        }
257        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
258            !strcmp(tok2, "endcidchar")) {
259          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
260          break;
261        }
262        if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
263              n1 >= 4 && (n1 & 1) == 0)) {
264          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
265          continue;
266        }
267        tok1[n1 - 1] = '\0';
268        if (sscanf(tok1 + 1, "%x", &code) != 1) {
269          error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap");
270          continue;
271        }
272        n1 = (n1 - 2) / 2;
273        addCIDs(code, code, n1, (CID)atoi(tok2));
274      }
275      pst->getToken(tok1, sizeof(tok1), &n1);
276    } else if (!strcmp(tok2, "begincidrange")) {
277      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
278        if (!strcmp(tok1, "endcidrange")) {
279          break;
280        }
281        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
282            !strcmp(tok2, "endcidrange") ||
283            !pst->getToken(tok3, sizeof(tok3), &n3) ||
284            !strcmp(tok3, "endcidrange")) {
285          error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap");
286          break;
287        }
288        if (tok1[0] == '<' && tok2[0] == '<' &&
289            n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
290          tok1[n1 - 1] = tok2[n1 - 1] = '\0';
291          sscanf(tok1 + 1, "%x", &start);
292          sscanf(tok2 + 1, "%x", &end);
293          n1 = (n1 - 2) / 2;
294          addCIDs(start, end, n1, (CID)atoi(tok3));
295        }
296      }
297      pst->getToken(tok1, sizeof(tok1), &n1);
298    } else {
299      strcpy(tok1, tok2);
300    }
301  }
302  delete pst;
303}
304
305CMap::CMap(GooString *collectionA, GooString *cMapNameA) {
306  int i;
307
308  collection = collectionA;
309  cMapName = cMapNameA;
310  isIdent = gFalse;
311  wMode = 0;
312  vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
313  for (i = 0; i < 256; ++i) {
314    vector[i].isVector = gFalse;
315    vector[i].cid = 0;
316  }
317  refCnt = 1;
318#if MULTITHREADED
319  gInitMutex(&mutex);
320#endif
321}
322
323CMap::CMap(GooString *collectionA, GooString *cMapNameA, int wModeA) {
324  collection = collectionA;
325  cMapName = cMapNameA;
326  isIdent = gTrue;
327  wMode = wModeA;
328  vector = NULL;
329  refCnt = 1;
330#if MULTITHREADED
331  gInitMutex(&mutex);
332#endif
333}
334
335void CMap::useCMap(CMapCache *cache, char *useName) {
336  GooString *useNameStr;
337  CMap *subCMap;
338
339  useNameStr = new GooString(useName);
340  // if cache is non-NULL, we already have a lock, and we can use
341  // CMapCache::getCMap() directly; otherwise, we need to use
342  // GlobalParams::getCMap() in order to acqure the lock need to use
343  // GlobalParams::getCMap
344  if (cache) {
345    subCMap = cache->getCMap(collection, useNameStr, NULL);
346  } else {
347    subCMap = globalParams->getCMap(collection, useNameStr);
348  }
349  delete useNameStr;
350  if (!subCMap) {
351    return;
352  }
353  isIdent = subCMap->isIdent;
354  if (subCMap->vector) {
355    copyVector(vector, subCMap->vector);
356  }
357  subCMap->decRefCnt();
358}
359
360void CMap::useCMap(CMapCache *cache, Object *obj) {
361  CMap *subCMap;
362
363  subCMap = CMap::parse(cache, collection, obj);
364  if (!subCMap) {
365    return;
366  }
367  isIdent = subCMap->isIdent;
368  if (subCMap->vector) {
369    copyVector(vector, subCMap->vector);
370  }
371  subCMap->decRefCnt();
372}
373
374void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
375  int i, j;
376
377  for (i = 0; i < 256; ++i) {
378    if (src[i].isVector) {
379      if (!dest[i].isVector) {
380        dest[i].isVector = gTrue;
381        dest[i].vector =
382          (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
383        for (j = 0; j < 256; ++j) {
384          dest[i].vector[j].isVector = gFalse;
385          dest[i].vector[j].cid = 0;
386        }
387      }
388      copyVector(dest[i].vector, src[i].vector);
389    } else {
390      if (dest[i].isVector) {
391        error(errSyntaxError, -1, "Collision in usecmap");
392      } else {
393        dest[i].cid = src[i].cid;
394      }
395    }
396  }
397}
398
399void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
400  CMapVectorEntry *vec;
401  CID cid;
402  int byte;
403  Guint i, j;
404
405  vec = vector;
406  for (i = nBytes - 1; i >= 1; --i) {
407    byte = (start >> (8 * i)) & 0xff;
408    if (!vec[byte].isVector) {
409      vec[byte].isVector = gTrue;
410      vec[byte].vector =
411          (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
412      for (j = 0; j < 256; ++j) {
413        vec[byte].vector[j].isVector = gFalse;
414        vec[byte].vector[j].cid = 0;
415      }
416    }
417    vec = vec[byte].vector;
418  }
419  cid = firstCID;
420  for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
421    if (vec[byte].isVector) {
422      error(errSyntaxError, -1,
423            "Invalid CID ({0:x} - {1:x} [{2:d} bytes]) in CMap",
424            start, end, nBytes);
425    } else {
426      vec[byte].cid = cid;
427    }
428    ++cid;
429  }
430}
431
432CMap::~CMap() {
433  delete collection;
434  delete cMapName;
435  if (vector) {
436    freeCMapVector(vector);
437  }
438#if MULTITHREADED
439  gDestroyMutex(&mutex);
440#endif
441}
442
443void CMap::freeCMapVector(CMapVectorEntry *vec) {
444  int i;
445
446  for (i = 0; i < 256; ++i) {
447    if (vec[i].isVector) {
448      freeCMapVector(vec[i].vector);
449    }
450  }
451  gfree(vec);
452}
453
454void CMap::incRefCnt() {
455#if MULTITHREADED
456  gLockMutex(&mutex);
457#endif
458  ++refCnt;
459#if MULTITHREADED
460  gUnlockMutex(&mutex);
461#endif
462}
463
464void CMap::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 CMap::match(GooString *collectionA, GooString *cMapNameA) {
480  return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
481}
482
483CID CMap::getCID(char *s, int len, CharCode *c, int *nUsed) {
484  CMapVectorEntry *vec;
485  CharCode cc;
486  int n, i;
487
488  vec = vector;
489  cc = 0;
490  n = 0;
491  while (vec && n < len) {
492    i = s[n++] & 0xff;
493    cc = (cc << 8) | i;
494    if (!vec[i].isVector) {
495      *c = cc;
496      *nUsed = n;
497      return vec[i].cid;
498    }
499    vec = vec[i].vector;
500  }
501  if (isIdent && len >= 2) {
502    // identity CMap
503    *nUsed = 2;
504    *c = cc = ((s[0] & 0xff) << 8) + (s[1] & 0xff);
505    return cc;
506  }
507  *nUsed = 1;
508  *c = s[0] & 0xff;
509  return 0;
510}
511
512void CMap::setReverseMapVector(Guint startCode, CMapVectorEntry *vec,
513 Guint *rmap, Guint rmapSize, Guint ncand) {
514  int i;
515
516  if (vec == 0) return;
517  for (i = 0;i < 256;i++) {
518    if (vec[i].isVector) {
519      setReverseMapVector((startCode+i) << 8,
520          vec[i].vector,rmap,rmapSize,ncand);
521    } else {
522      Guint cid = vec[i].cid;
523
524      if (cid < rmapSize) {
525        Guint cand;
526
527        for (cand = 0;cand < ncand;cand++) {
528          Guint code = startCode+i;
529          Guint idx = cid*ncand+cand;
530          if (rmap[idx] == 0) {
531            rmap[idx] = code;
532            break;
533          } else if (rmap[idx] == code) {
534            break;
535          }
536        }
537      }
538    }
539  }
540}
541
542void CMap::setReverseMap(Guint *rmap, Guint rmapSize, Guint ncand) {
543  setReverseMapVector(0,vector,rmap,rmapSize,ncand);
544}
545
546//------------------------------------------------------------------------
547
548CMapCache::CMapCache() {
549  int i;
550
551  for (i = 0; i < cMapCacheSize; ++i) {
552    cache[i] = NULL;
553  }
554}
555
556CMapCache::~CMapCache() {
557  int i;
558
559  for (i = 0; i < cMapCacheSize; ++i) {
560    if (cache[i]) {
561      cache[i]->decRefCnt();
562    }
563  }
564}
565
566CMap *CMapCache::getCMap(GooString *collection, GooString *cMapName, Stream *stream) {
567  CMap *cmap;
568  int i, j;
569
570  if (cache[0] && cache[0]->match(collection, cMapName)) {
571    cache[0]->incRefCnt();
572    return cache[0];
573  }
574  for (i = 1; i < cMapCacheSize; ++i) {
575    if (cache[i] && cache[i]->match(collection, cMapName)) {
576      cmap = cache[i];
577      for (j = i; j >= 1; --j) {
578        cache[j] = cache[j - 1];
579      }
580      cache[0] = cmap;
581      cmap->incRefCnt();
582      return cmap;
583    }
584  }
585  if ((cmap = CMap::parse(this, collection, cMapName, stream))) {
586    if (cache[cMapCacheSize - 1]) {
587      cache[cMapCacheSize - 1]->decRefCnt();
588    }
589    for (j = cMapCacheSize - 1; j >= 1; --j) {
590      cache[j] = cache[j - 1];
591    }
592    cache[0] = cmap;
593    cmap->incRefCnt();
594    return cmap;
595  }
596  return NULL;
597}
Note: See TracBrowser for help on using the browser.