1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
23 #include "GlobalParams.h"
24 #include "PSTokenizer.h"
27 //------------------------------------------------------------------------
29 struct CMapVectorEntry
{
32 CMapVectorEntry
*vector
;
37 //------------------------------------------------------------------------
39 static int getCharFromFile(void *data
) {
40 return myfgetc((myFILE
*)data
);
43 //------------------------------------------------------------------------
45 CMap
*CMap::parse(CMapCache
*cache
, GString
*collectionA
,
50 char tok1
[256], tok2
[256], tok3
[256];
52 Guint start
, end
, code
;
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());
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")) {
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")) {
87 if (!pst
->getToken(tok2
, sizeof(tok2
), &n2
) ||
88 !strcmp(tok2
, "endcodespacerange")) {
89 error(-1, "Illegal entry in codespacerange block in CMap");
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
);
98 cmap
->addCodeSpace(cmap
->vector
, start
, end
, n1
);
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")) {
107 if (!pst
->getToken(tok2
, sizeof(tok2
), &n2
) ||
108 !strcmp(tok2
, "endcidchar")) {
109 error(-1, "Illegal entry in cidchar block in CMap");
112 if (!(tok1
[0] == '<' && tok1
[n1
- 1] == '>' &&
113 n1
>= 4 && (n1
& 1) == 0)) {
114 error(-1, "Illegal entry in cidchar block in CMap");
118 if (sscanf(tok1
+ 1, "%x", &code
) != 1) {
119 error(-1, "Illegal entry in cidchar block in CMap");
123 cmap
->addCIDs(code
, code
, n1
, (CID
)atoi(tok2
));
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")) {
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");
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
);
144 cmap
->addCIDs(start
, end
, n1
, (CID
)atoi(tok3
));
147 pst
->getToken(tok1
, sizeof(tok1
), &n1
);
159 CMap::CMap(GString
*collectionA
, GString
*cMapNameA
) {
162 collection
= collectionA
;
163 cMapName
= cMapNameA
;
165 vector
= (CMapVectorEntry
*)gmallocn(256, sizeof(CMapVectorEntry
));
166 for (i
= 0; i
< 256; ++i
) {
167 vector
[i
].isVector
= gFalse
;
176 CMap::CMap(GString
*collectionA
, GString
*cMapNameA
, int wModeA
) {
177 collection
= collectionA
;
178 cMapName
= cMapNameA
;
187 void CMap::useCMap(CMapCache
*cache
, char *useName
) {
191 useNameStr
= new GString(useName
);
192 subCMap
= cache
->getCMap(collection
, useNameStr
);
197 copyVector(vector
, subCMap
->vector
);
198 subCMap
->decRefCnt();
201 void CMap::copyVector(CMapVectorEntry
*dest
, CMapVectorEntry
*src
) {
204 for (i
= 0; i
< 256; ++i
) {
205 if (src
[i
].isVector
) {
206 if (!dest
[i
].isVector
) {
207 dest
[i
].isVector
= gTrue
;
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;
215 copyVector(dest
[i
].vector
, src
[i
].vector
);
217 if (dest
[i
].isVector
) {
218 error(-1, "Collision in usecmap");
220 dest
[i
].cid
= src
[i
].cid
;
226 void CMap::addCodeSpace(CMapVectorEntry
*vec
, Guint start
, Guint end
,
229 int startByte
, endByte
, i
, j
;
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
;
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;
246 addCodeSpace(vec
[i
].vector
, start2
, end2
, nBytes
- 1);
251 void CMap::addCIDs(Guint start
, Guint end
, Guint nBytes
, CID firstCID
) {
252 CMapVectorEntry
*vec
;
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
);
265 vec
= vec
[byte
].vector
;
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
);
283 freeCMapVector(vector
);
286 gDestroyMutex(&mutex
);
290 void CMap::freeCMapVector(CMapVectorEntry
*vec
) {
293 for (i
= 0; i
< 256; ++i
) {
294 if (vec
[i
].isVector
) {
295 freeCMapVector(vec
[i
].vector
);
301 void CMap::incRefCnt() {
307 gUnlockMutex(&mutex
);
311 void CMap::decRefCnt() {
317 done
= --refCnt
== 0;
319 gUnlockMutex(&mutex
);
326 GBool
CMap::match(GString
*collectionA
, GString
*cMapNameA
) {
327 return !collection
->cmp(collectionA
) && !cMapName
->cmp(cMapNameA
);
330 CID
CMap::getCID(char *s
, int len
, int *nUsed
) {
331 CMapVectorEntry
*vec
;
334 if (!(vec
= vector
)) {
340 return ((s
[0] & 0xff) << 8) + (s
[1] & 0xff);
349 if (!vec
[i
].isVector
) {
357 //------------------------------------------------------------------------
359 CMapCache::CMapCache() {
362 for (i
= 0; i
< cMapCacheSize
; ++i
) {
367 CMapCache::~CMapCache() {
370 for (i
= 0; i
< cMapCacheSize
; ++i
) {
372 cache
[i
]->decRefCnt();
377 CMap
*CMapCache::getCMap(GString
*collection
, GString
*cMapName
) {
381 if (cache
[0] && cache
[0]->match(collection
, cMapName
)) {
382 cache
[0]->incRefCnt();
385 for (i
= 1; i
< cMapCacheSize
; ++i
) {
386 if (cache
[i
] && cache
[i
]->match(collection
, cMapName
)) {
388 for (j
= i
; j
>= 1; --j
) {
389 cache
[j
] = cache
[j
- 1];
396 if ((cmap
= CMap::parse(this, collection
, cMapName
))) {
397 if (cache
[cMapCacheSize
- 1]) {
398 cache
[cMapCacheSize
- 1]->decRefCnt();
400 for (j
= cMapCacheSize
- 1; j
>= 1; --j
) {
401 cache
[j
] = cache
[j
- 1];