]> git.ipfire.org Git - thirdparty/cups.git/blame - pdftops/CMap.cxx
Load cups into easysw/current.
[thirdparty/cups.git] / pdftops / CMap.cxx
CommitLineData
ef416fc2 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 "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
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, 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
159CMap::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
176CMap::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
187void 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
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(GString *collectionA, GString *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(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}