~ubuntu-branches/ubuntu/wily/luatex/wily

« back to all changes in this revision

Viewing changes to source/libs/xpdf/xpdf-3.02/xpdf/CMap.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-04-29 00:47:19 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100429004719-o42etkqe90n97b9e
Tags: 0.60.1-1
* new upstream release, adapt build-script patch
* disable patch: upstream-epstopdf_cc_no_xpdf_patching, included upstream
* disable patch: libpoppler-0.12, not needed anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//========================================================================
 
2
//
 
3
// CMap.cc
 
4
//
 
5
// Copyright 2001-2003 Glyph & Cog, LLC
 
6
//
 
7
//========================================================================
 
8
 
 
9
#include <aconf.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 "gmem.h"
 
20
#include "gfile.h"
 
21
#include "GString.h"
 
22
#include "Error.h"
 
23
#include "GlobalParams.h"
 
24
#include "PSTokenizer.h"
 
25
#include "CMap.h"
 
26
 
 
27
//------------------------------------------------------------------------
 
28
 
 
29
struct CMapVectorEntry {
 
30
  GBool isVector;
 
31
  union {
 
32
    CMapVectorEntry *vector;
 
33
    CID cid;
 
34
  };
 
35
};
 
36
 
 
37
//------------------------------------------------------------------------
 
38
 
 
39
static int getCharFromFile(void *data) {
 
40
  return fgetc((FILE *)data);
 
41
}
 
42
 
 
43
//------------------------------------------------------------------------
 
44
 
 
45
CMap *CMap::parse(CMapCache *cache, GString *collectionA,
 
46
                  GString *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
 
 
159
CMap::CMap(GString *collectionA, GString *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
 
 
176
CMap::CMap(GString *collectionA, GString *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
 
 
187
void CMap::useCMap(CMapCache *cache, char *useName) {
 
188
  GString *useNameStr;
 
189
  CMap *subCMap;
 
190
 
 
191
  useNameStr = new GString(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
 
 
201
void 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
 
 
226
void 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
 
 
251
void 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
 
 
279
CMap::~CMap() {
 
280
  delete collection;
 
281
  delete cMapName;
 
282
  if (vector) {
 
283
    freeCMapVector(vector);
 
284
  }
 
285
#if MULTITHREADED
 
286
  gDestroyMutex(&mutex);
 
287
#endif
 
288
}
 
289
 
 
290
void 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
 
 
301
void CMap::incRefCnt() {
 
302
#if MULTITHREADED
 
303
  gLockMutex(&mutex);
 
304
#endif
 
305
  ++refCnt;
 
306
#if MULTITHREADED
 
307
  gUnlockMutex(&mutex);
 
308
#endif
 
309
}
 
310
 
 
311
void 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
 
 
326
GBool CMap::match(GString *collectionA, GString *cMapNameA) {
 
327
  return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
 
328
}
 
329
 
 
330
CID 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
 
 
359
CMapCache::CMapCache() {
 
360
  int i;
 
361
 
 
362
  for (i = 0; i < cMapCacheSize; ++i) {
 
363
    cache[i] = NULL;
 
364
  }
 
365
}
 
366
 
 
367
CMapCache::~CMapCache() {
 
368
  int i;
 
369
 
 
370
  for (i = 0; i < cMapCacheSize; ++i) {
 
371
    if (cache[i]) {
 
372
      cache[i]->decRefCnt();
 
373
    }
 
374
  }
 
375
}
 
376
 
 
377
CMap *CMapCache::getCMap(GString *collection, GString *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
}