upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / CMap.cc
blob25f3af75e7066d81c3a5dc7ffb22d1cc3860cbaf
1 //========================================================================
2 //
3 // CMap.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
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"
27 //------------------------------------------------------------------------
29 struct CMapVectorEntry {
30 GBool isVector;
31 union {
32 CMapVectorEntry *vector;
33 CID cid;
37 //------------------------------------------------------------------------
39 static int getCharFromFile(void *data) {
40 return fgetc((FILE *)data);
43 //------------------------------------------------------------------------
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;
54 if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
56 // Check for an identity CMap.
57 if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
58 return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
60 if (!cMapNameA->cmp("Identity-V")) {
61 return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
64 error(-1, "Couldn't find '%s' CMap file for '%s' collection",
65 cMapNameA->getCString(), collectionA->getCString());
66 return NULL;
69 cmap = new CMap(collectionA->copy(), cMapNameA->copy());
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);
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;
87 if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
88 !strcmp(tok2, "endcodespacerange")) {
89 error(-1, "Illegal entry in codespacerange block in CMap");
90 break;
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);
101 pst->getToken(tok1, sizeof(tok1), &n1);
102 } else if (!strcmp(tok2, "begincidrange")) {
103 while (pst->getToken(tok1, sizeof(tok1), &n1)) {
104 if (!strcmp(tok1, "endcidrange")) {
105 break;
107 if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
108 !strcmp(tok2, "endcidrange") ||
109 !pst->getToken(tok3, sizeof(tok3), &n3) ||
110 !strcmp(tok3, "endcidrange")) {
111 error(-1, "Illegal entry in cidrange block in CMap");
112 break;
114 if (tok1[0] == '<' && tok2[0] == '<' &&
115 n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
116 tok1[n1 - 1] = tok2[n1 - 1] = '\0';
117 sscanf(tok1 + 1, "%x", &start);
118 sscanf(tok2 + 1, "%x", &end);
119 n1 = (n1 - 2) / 2;
120 cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
123 pst->getToken(tok1, sizeof(tok1), &n1);
124 } else {
125 strcpy(tok1, tok2);
128 delete pst;
130 fclose(f);
132 return cmap;
135 CMap::CMap(GString *collectionA, GString *cMapNameA) {
136 int i;
138 collection = collectionA;
139 cMapName = cMapNameA;
140 wMode = 0;
141 vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
142 for (i = 0; i < 256; ++i) {
143 vector[i].isVector = gFalse;
144 vector[i].cid = 0;
146 refCnt = 1;
147 #if MULTITHREADED
148 gInitMutex(&mutex);
149 #endif
152 CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
153 collection = collectionA;
154 cMapName = cMapNameA;
155 wMode = wModeA;
156 vector = NULL;
157 refCnt = 1;
158 #if MULTITHREADED
159 gInitMutex(&mutex);
160 #endif
163 void CMap::useCMap(CMapCache *cache, char *useName) {
164 GString *useNameStr;
165 CMap *subCMap;
167 useNameStr = new GString(useName);
168 subCMap = cache->getCMap(collection, useNameStr);
169 delete useNameStr;
170 if (!subCMap) {
171 return;
173 copyVector(vector, subCMap->vector);
174 subCMap->decRefCnt();
177 void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
178 int i, j;
180 for (i = 0; i < 256; ++i) {
181 if (src[i].isVector) {
182 if (!dest[i].isVector) {
183 dest[i].isVector = gTrue;
184 dest[i].vector =
185 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
186 for (j = 0; j < 256; ++j) {
187 dest[i].vector[j].isVector = gFalse;
188 dest[i].vector[j].cid = 0;
191 copyVector(dest[i].vector, src[i].vector);
192 } else {
193 if (dest[i].isVector) {
194 error(-1, "Collision in usecmap");
195 } else {
196 dest[i].cid = src[i].cid;
202 void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
203 Guint nBytes) {
204 Guint start2, end2;
205 int startByte, endByte, i, j;
207 if (nBytes > 1) {
208 startByte = (start >> (8 * (nBytes - 1))) & 0xff;
209 endByte = (end >> (8 * (nBytes - 1))) & 0xff;
210 start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
211 end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
212 for (i = startByte; i <= endByte; ++i) {
213 if (!vec[i].isVector) {
214 vec[i].isVector = gTrue;
215 vec[i].vector =
216 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
217 for (j = 0; j < 256; ++j) {
218 vec[i].vector[j].isVector = gFalse;
219 vec[i].vector[j].cid = 0;
222 addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
227 void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
228 CMapVectorEntry *vec;
229 CID cid;
230 int byte;
231 Guint i;
233 vec = vector;
234 for (i = nBytes - 1; i >= 1; --i) {
235 byte = (start >> (8 * i)) & 0xff;
236 if (!vec[byte].isVector) {
237 error(-1, "Invalid CID (%*x - %*x) in CMap",
238 2*nBytes, start, 2*nBytes, end);
239 return;
241 vec = vec[byte].vector;
243 cid = firstCID;
244 for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
245 if (vec[byte].isVector) {
246 error(-1, "Invalid CID (%*x - %*x) in CMap",
247 2*nBytes, start, 2*nBytes, end);
248 } else {
249 vec[byte].cid = cid;
251 ++cid;
255 CMap::~CMap() {
256 delete collection;
257 delete cMapName;
258 if (vector) {
259 freeCMapVector(vector);
261 #if MULTITHREADED
262 gDestroyMutex(&mutex);
263 #endif
266 void CMap::freeCMapVector(CMapVectorEntry *vec) {
267 int i;
269 for (i = 0; i < 256; ++i) {
270 if (vec[i].isVector) {
271 freeCMapVector(vec[i].vector);
274 gfree(vec);
277 void CMap::incRefCnt() {
278 #if MULTITHREADED
279 gLockMutex(&mutex);
280 #endif
281 ++refCnt;
282 #if MULTITHREADED
283 gUnlockMutex(&mutex);
284 #endif
287 void CMap::decRefCnt() {
288 GBool done;
290 #if MULTITHREADED
291 gLockMutex(&mutex);
292 #endif
293 done = --refCnt == 0;
294 #if MULTITHREADED
295 gUnlockMutex(&mutex);
296 #endif
297 if (done) {
298 delete this;
302 GBool CMap::match(GString *collectionA, GString *cMapNameA) {
303 return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
306 CID CMap::getCID(char *s, int len, int *nUsed) {
307 CMapVectorEntry *vec;
308 int n, i;
310 if (!(vec = vector)) {
311 // identity CMap
312 *nUsed = 2;
313 if (len < 2) {
314 return 0;
316 return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
318 n = 0;
319 while (1) {
320 if (n >= len) {
321 *nUsed = n;
322 return 0;
324 i = s[n++] & 0xff;
325 if (!vec[i].isVector) {
326 *nUsed = n;
327 return vec[i].cid;
329 vec = vec[i].vector;
333 //------------------------------------------------------------------------
335 CMapCache::CMapCache() {
336 int i;
338 for (i = 0; i < cMapCacheSize; ++i) {
339 cache[i] = NULL;
343 CMapCache::~CMapCache() {
344 int i;
346 for (i = 0; i < cMapCacheSize; ++i) {
347 if (cache[i]) {
348 cache[i]->decRefCnt();
353 CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
354 CMap *cmap;
355 int i, j;
357 if (cache[0] && cache[0]->match(collection, cMapName)) {
358 cache[0]->incRefCnt();
359 return cache[0];
361 for (i = 1; i < cMapCacheSize; ++i) {
362 if (cache[i] && cache[i]->match(collection, cMapName)) {
363 cmap = cache[i];
364 for (j = i; j >= 1; --j) {
365 cache[j] = cache[j - 1];
367 cache[0] = cmap;
368 cmap->incRefCnt();
369 return cmap;
372 if ((cmap = CMap::parse(this, collection, cMapName))) {
373 if (cache[cMapCacheSize - 1]) {
374 cache[cMapCacheSize - 1]->decRefCnt();
376 for (j = cMapCacheSize - 1; j >= 1; --j) {
377 cache[j] = cache[j - 1];
379 cache[0] = cmap;
380 cmap->incRefCnt();
381 return cmap;
383 return NULL;