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

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

First import

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