source: trunk/poppler/mypoppler/poppler/CMap.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: 10.6 KB
RevLine 
[2]1//========================================================================
2//
3// CMap.cc
4//
5// Copyright 2001-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
[257]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 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
[2]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
42//------------------------------------------------------------------------
43
44struct CMapVectorEntry {
45  GBool isVector;
46  union {
47    CMapVectorEntry *vector;
48    CID cid;
49  };
50};
51
52//------------------------------------------------------------------------
53
54static int getCharFromFile(void *data) {
55  return fgetc((FILE *)data);
56}
57
58//------------------------------------------------------------------------
59
60CMap *CMap::parse(CMapCache *cache, GooString *collectionA,
61                  GooString *cMapNameA) {
62  FILE *f;
63  CMap *cmap;
64  PSTokenizer *pst;
65  char tok1[256], tok2[256], tok3[256];
66  int n1, n2, n3;
67  Guint start, end, code;
68
69  if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
70
71    // Check for an identity CMap.
72    if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
73      return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
74    }
75    if (!cMapNameA->cmp("Identity-V")) {
76      return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
77    }
78
79    error(-1, "Couldn't find '%s' CMap file for '%s' collection",
80          cMapNameA->getCString(), collectionA->getCString());
81    return NULL;
82  }
83
84  cmap = new CMap(collectionA->copy(), cMapNameA->copy());
85
86  pst = new PSTokenizer(&getCharFromFile, f);
87  pst->getToken(tok1, sizeof(tok1), &n1);
88  while (pst->getToken(tok2, sizeof(tok2), &n2)) {
89    if (!strcmp(tok2, "usecmap")) {
90      if (tok1[0] == '/') {
91        cmap->useCMap(cache, tok1 + 1);
92      }
93      pst->getToken(tok1, sizeof(tok1), &n1);
94    } else if (!strcmp(tok1, "/WMode")) {
95      cmap->wMode = atoi(tok2);
96      pst->getToken(tok1, sizeof(tok1), &n1);
97    } else if (!strcmp(tok2, "begincodespacerange")) {
98      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
99        if (!strcmp(tok1, "endcodespacerange")) {
100          break;
101        }
102        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
103            !strcmp(tok2, "endcodespacerange")) {
104          error(-1, "Illegal entry in codespacerange block in CMap");
105          break;
106        }
107        if (tok1[0] == '<' && tok2[0] == '<' &&
108            n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
109          tok1[n1 - 1] = tok2[n1 - 1] = '\0';
110          sscanf(tok1 + 1, "%x", &start);
111          sscanf(tok2 + 1, "%x", &end);
112          n1 = (n1 - 2) / 2;
113          cmap->addCodeSpace(cmap->vector, start, end, n1);
114        }
115      }
116      pst->getToken(tok1, sizeof(tok1), &n1);
117    } else if (!strcmp(tok2, "begincidchar")) {
118      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
119        if (!strcmp(tok1, "endcidchar")) {
120          break;
121        }
122        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
123            !strcmp(tok2, "endcidchar")) {
124          error(-1, "Illegal entry in cidchar block in CMap");
125          break;
126        }
127        if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
128              n1 >= 4 && (n1 & 1) == 0)) {
129          error(-1, "Illegal entry in cidchar block in CMap");
130          continue;
131        }
132        tok1[n1 - 1] = '\0';
133        if (sscanf(tok1 + 1, "%x", &code) != 1) {
134          error(-1, "Illegal entry in cidchar block in CMap");
135          continue;
136        }
137        n1 = (n1 - 2) / 2;
138        cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
139      }
140      pst->getToken(tok1, sizeof(tok1), &n1);
141    } else if (!strcmp(tok2, "begincidrange")) {
142      while (pst->getToken(tok1, sizeof(tok1), &n1)) {
143        if (!strcmp(tok1, "endcidrange")) {
144          break;
145        }
146        if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
147            !strcmp(tok2, "endcidrange") ||
148            !pst->getToken(tok3, sizeof(tok3), &n3) ||
149            !strcmp(tok3, "endcidrange")) {
150          error(-1, "Illegal entry in cidrange block in CMap");
151          break;
152        }
153        if (tok1[0] == '<' && tok2[0] == '<' &&
154            n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
155          tok1[n1 - 1] = tok2[n1 - 1] = '\0';
156          sscanf(tok1 + 1, "%x", &start);
157          sscanf(tok2 + 1, "%x", &end);
158          n1 = (n1 - 2) / 2;
159          cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
160        }
161      }
162      pst->getToken(tok1, sizeof(tok1), &n1);
163    } else {
164      strcpy(tok1, tok2);
165    }
166  }
167  delete pst;
168
169  fclose(f);
170
171  return cmap;
172}
173
174CMap::CMap(GooString *collectionA, GooString *cMapNameA) {
175  int i;
176
177  collection = collectionA;
178  cMapName = cMapNameA;
179  wMode = 0;
180  vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
181  for (i = 0; i < 256; ++i) {
182    vector[i].isVector = gFalse;
183    vector[i].cid = 0;
184  }
185  refCnt = 1;
186#if MULTITHREADED
187  gInitMutex(&mutex);
188#endif
189}
190
191CMap::CMap(GooString *collectionA, GooString *cMapNameA, int wModeA) {
192  collection = collectionA;
193  cMapName = cMapNameA;
194  wMode = wModeA;
195  vector = NULL;
196  refCnt = 1;
197#if MULTITHREADED
198  gInitMutex(&mutex);
199#endif
200}
201
202void CMap::useCMap(CMapCache *cache, char *useName) {
203  GooString *useNameStr;
204  CMap *subCMap;
205
206  useNameStr = new GooString(useName);
207  subCMap = cache->getCMap(collection, useNameStr);
208  delete useNameStr;
209  if (!subCMap) {
210    return;
211  }
212  copyVector(vector, subCMap->vector);
213  subCMap->decRefCnt();
214}
215
216void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
217  int i, j;
218
219  for (i = 0; i < 256; ++i) {
220    if (src[i].isVector) {
221      if (!dest[i].isVector) {
222        dest[i].isVector = gTrue;
223        dest[i].vector =
224          (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
225        for (j = 0; j < 256; ++j) {
226          dest[i].vector[j].isVector = gFalse;
227          dest[i].vector[j].cid = 0;
228        }
229      }
230      copyVector(dest[i].vector, src[i].vector);
231    } else {
232      if (dest[i].isVector) {
233        error(-1, "Collision in usecmap");
234      } else {
235        dest[i].cid = src[i].cid;
236      }
237    }
238  }
239}
240
241void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
242                        Guint nBytes) {
243  Guint start2, end2;
244  int startByte, endByte, i, j;
245
246  if (nBytes > 1) {
247    startByte = (start >> (8 * (nBytes - 1))) & 0xff;
248    endByte = (end >> (8 * (nBytes - 1))) & 0xff;
249    start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
250    end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
251    for (i = startByte; i <= endByte; ++i) {
252      if (!vec[i].isVector) {
253        vec[i].isVector = gTrue;
254        vec[i].vector =
255          (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
256        for (j = 0; j < 256; ++j) {
257          vec[i].vector[j].isVector = gFalse;
258          vec[i].vector[j].cid = 0;
259        }
260      }
261      addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
262    }
263  }
264}
265
266void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
267  CMapVectorEntry *vec;
268  CID cid;
269  int byte;
270  Guint i;
271
272  vec = vector;
273  for (i = nBytes - 1; i >= 1; --i) {
274    byte = (start >> (8 * i)) & 0xff;
275    if (!vec[byte].isVector) {
276      error(-1, "Invalid CID (%0*x - %0*x) in CMap",
277            2*nBytes, start, 2*nBytes, end);
278      return;
279    }
280    vec = vec[byte].vector;
281  }
282  cid = firstCID;
283  for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
284    if (vec[byte].isVector) {
285      error(-1, "Invalid CID (%0*x - %0*x) in CMap",
286            2*nBytes, start, 2*nBytes, end);
287    } else {
288      vec[byte].cid = cid;
289    }
290    ++cid;
291  }
292}
293
294CMap::~CMap() {
295  delete collection;
296  delete cMapName;
297  if (vector) {
298    freeCMapVector(vector);
299  }
300#if MULTITHREADED
301  gDestroyMutex(&mutex);
302#endif
303}
304
305void CMap::freeCMapVector(CMapVectorEntry *vec) {
306  int i;
307
308  for (i = 0; i < 256; ++i) {
309    if (vec[i].isVector) {
310      freeCMapVector(vec[i].vector);
311    }
312  }
313  gfree(vec);
314}
315
316void CMap::incRefCnt() {
317#if MULTITHREADED
318  gLockMutex(&mutex);
319#endif
320  ++refCnt;
321#if MULTITHREADED
322  gUnlockMutex(&mutex);
323#endif
324}
325
326void CMap::decRefCnt() {
327  GBool done;
328
329#if MULTITHREADED
330  gLockMutex(&mutex);
331#endif
332  done = --refCnt == 0;
333#if MULTITHREADED
334  gUnlockMutex(&mutex);
335#endif
336  if (done) {
337    delete this;
338  }
339}
340
341GBool CMap::match(GooString *collectionA, GooString *cMapNameA) {
342  return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
343}
344
345CID CMap::getCID(char *s, int len, int *nUsed) {
346  CMapVectorEntry *vec;
347  int n, i;
348
349  if (!(vec = vector)) {
350    // identity CMap
351    *nUsed = 2;
352    if (len < 2) {
353      return 0;
354    }
355    return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
356  }
357  n = 0;
358  while (1) {
359    if (n >= len) {
360      *nUsed = n;
361      return 0;
362    }
363    i = s[n++] & 0xff;
364    if (!vec[i].isVector) {
365      *nUsed = n;
366      return vec[i].cid;
367    }
368    vec = vec[i].vector;
369  }
370}
371
[250]372void CMap::setReverseMapVector(Guint startCode, CMapVectorEntry *vec,
373 Guint *rmap, Guint rmapSize, Guint ncand) {
374  int i;
375
376  if (vec == 0) return;
377  for (i = 0;i < 256;i++) {
378    if (vec[i].isVector) {
379      setReverseMapVector((startCode+i) << 8,
380          vec[i].vector,rmap,rmapSize,ncand);
381    } else {
382      Guint cid = vec[i].cid;
383
384      if (cid < rmapSize) {
[257]385        Guint cand;
[250]386
387        for (cand = 0;cand < ncand;cand++) {
388          Guint code = startCode+i;
389          Guint idx = cid*ncand+cand;
390          if (rmap[idx] == 0) {
391            rmap[idx] = code;
392            break;
393          } else if (rmap[idx] == code) {
394            break;
395          }
396        }
397      }
398    }
399  }
400}
401
402void CMap::setReverseMap(Guint *rmap, Guint rmapSize, Guint ncand) {
403  setReverseMapVector(0,vector,rmap,rmapSize,ncand);
404}
405
[2]406//------------------------------------------------------------------------
407
408CMapCache::CMapCache() {
409  int i;
410
411  for (i = 0; i < cMapCacheSize; ++i) {
412    cache[i] = NULL;
413  }
414}
415
416CMapCache::~CMapCache() {
417  int i;
418
419  for (i = 0; i < cMapCacheSize; ++i) {
420    if (cache[i]) {
421      cache[i]->decRefCnt();
422    }
423  }
424}
425
426CMap *CMapCache::getCMap(GooString *collection, GooString *cMapName) {
427  CMap *cmap;
428  int i, j;
429
430  if (cache[0] && cache[0]->match(collection, cMapName)) {
431    cache[0]->incRefCnt();
432    return cache[0];
433  }
434  for (i = 1; i < cMapCacheSize; ++i) {
435    if (cache[i] && cache[i]->match(collection, cMapName)) {
436      cmap = cache[i];
437      for (j = i; j >= 1; --j) {
438        cache[j] = cache[j - 1];
439      }
440      cache[0] = cmap;
441      cmap->incRefCnt();
442      return cmap;
443    }
444  }
445  if ((cmap = CMap::parse(this, collection, cMapName))) {
446    if (cache[cMapCacheSize - 1]) {
447      cache[cMapCacheSize - 1]->decRefCnt();
448    }
449    for (j = cMapCacheSize - 1; j >= 1; --j) {
450      cache[j] = cache[j - 1];
451    }
452    cache[0] = cmap;
453    cmap->incRefCnt();
454    return cmap;
455  }
456  return NULL;
457}
Note: See TracBrowser for help on using the repository browser.