1 //========================================================================
5 // Copyright 2001-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
22 #include "GlobalParams.h"
23 #include "PSTokenizer.h"
26 //------------------------------------------------------------------------
28 struct CMapVectorEntry {
31 CMapVectorEntry *vector;
36 //------------------------------------------------------------------------
38 static int getCharFromFile(void *data) {
39 return fgetc((FILE *)data);
42 //------------------------------------------------------------------------
44 CMap *CMap::parse(CMapCache *cache, GString *collectionA,
49 char tok1[256], tok2[256], tok3[256];
53 if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
55 // Check for an identity CMap.
56 if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
57 return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
59 if (!cMapNameA->cmp("Identity-V")) {
60 return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
63 error(-1, "Couldn't find '%s' CMap file for '%s' collection",
64 cMapNameA->getCString(), collectionA->getCString());
68 cmap = new CMap(collectionA->copy(), cMapNameA->copy());
70 pst = new PSTokenizer(&getCharFromFile, f);
71 pst->getToken(tok1, sizeof(tok1), &n1);
72 while (pst->getToken(tok2, sizeof(tok2), &n2)) {
73 if (!strcmp(tok2, "usecmap")) {
75 cmap->useCMap(cache, tok1 + 1);
77 pst->getToken(tok1, sizeof(tok1), &n1);
78 } else if (!strcmp(tok1, "/WMode")) {
79 cmap->wMode = atoi(tok2);
80 pst->getToken(tok1, sizeof(tok1), &n1);
81 } else if (!strcmp(tok2, "begincodespacerange")) {
82 while (pst->getToken(tok1, sizeof(tok1), &n1)) {
83 if (!strcmp(tok1, "endcodespacerange")) {
86 if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
87 !strcmp(tok2, "endcodespacerange")) {
88 error(-1, "Illegal entry in codespacerange block in CMap");
91 if (tok1[0] == '<' && tok2[0] == '<' &&
92 n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
93 tok1[n1 - 1] = tok2[n1 - 1] = '\0';
94 sscanf(tok1 + 1, "%x", &start);
95 sscanf(tok2 + 1, "%x", &end);
97 cmap->addCodeSpace(cmap->vector, start, end, n1);
100 pst->getToken(tok1, sizeof(tok1), &n1);
101 } else if (!strcmp(tok2, "begincidrange")) {
102 while (pst->getToken(tok1, sizeof(tok1), &n1)) {
103 if (!strcmp(tok1, "endcidrange")) {
106 if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
107 !strcmp(tok2, "endcidrange") ||
108 !pst->getToken(tok3, sizeof(tok3), &n3) ||
109 !strcmp(tok3, "endcidrange")) {
110 error(-1, "Illegal entry in cidrange block in CMap");
113 if (tok1[0] == '<' && tok2[0] == '<' &&
114 n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
115 tok1[n1 - 1] = tok2[n1 - 1] = '\0';
116 sscanf(tok1 + 1, "%x", &start);
117 sscanf(tok2 + 1, "%x", &end);
119 cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
122 pst->getToken(tok1, sizeof(tok1), &n1);
134 CMap::CMap(GString *collectionA, GString *cMapNameA) {
137 collection = collectionA;
138 cMapName = cMapNameA;
140 vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
141 for (i = 0; i < 256; ++i) {
142 vector[i].isVector = gFalse;
148 CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
149 collection = collectionA;
150 cMapName = cMapNameA;
156 void CMap::useCMap(CMapCache *cache, char *useName) {
160 useNameStr = new GString(useName);
161 subCMap = cache->getCMap(collection, useNameStr);
166 copyVector(vector, subCMap->vector);
167 subCMap->decRefCnt();
170 void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
173 for (i = 0; i < 256; ++i) {
174 if (src[i].isVector) {
175 if (!dest[i].isVector) {
176 dest[i].isVector = gTrue;
178 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
179 for (j = 0; j < 256; ++j) {
180 dest[i].vector[j].isVector = gFalse;
181 dest[i].vector[j].cid = 0;
184 copyVector(dest[i].vector, src[i].vector);
186 if (dest[i].isVector) {
187 error(-1, "Collision in usecmap");
189 dest[i].cid = src[i].cid;
195 void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
198 int startByte, endByte, i, j;
201 startByte = (start >> (8 * (nBytes - 1))) & 0xff;
202 endByte = (end >> (8 * (nBytes - 1))) & 0xff;
203 start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
204 end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
205 for (i = startByte; i <= endByte; ++i) {
206 if (!vec[i].isVector) {
207 vec[i].isVector = gTrue;
209 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
210 for (j = 0; j < 256; ++j) {
211 vec[i].vector[j].isVector = gFalse;
212 vec[i].vector[j].cid = 0;
215 addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
220 void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
221 CMapVectorEntry *vec;
227 for (i = nBytes - 1; i >= 1; --i) {
228 byte = (start >> (8 * i)) & 0xff;
229 if (!vec[byte].isVector) {
230 error(-1, "Invalid CID (%*x - %*x) in CMap",
231 2*nBytes, start, 2*nBytes, end);
234 vec = vec[byte].vector;
237 for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
238 if (vec[byte].isVector) {
239 error(-1, "Invalid CID (%*x - %*x) in CMap",
240 2*nBytes, start, 2*nBytes, end);
252 freeCMapVector(vector);
256 void CMap::freeCMapVector(CMapVectorEntry *vec) {
259 for (i = 0; i < 256; ++i) {
260 if (vec[i].isVector) {
261 freeCMapVector(vec[i].vector);
267 void CMap::incRefCnt() {
271 void CMap::decRefCnt() {
277 GBool CMap::match(GString *collectionA, GString *cMapNameA) {
278 return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
281 CID CMap::getCID(char *s, int len, int *nUsed) {
282 CMapVectorEntry *vec;
285 if (!(vec = vector)) {
291 return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
300 if (!vec[i].isVector) {
308 //------------------------------------------------------------------------
310 CMapCache::CMapCache() {
313 for (i = 0; i < cMapCacheSize; ++i) {
318 CMapCache::~CMapCache() {
321 for (i = 0; i < cMapCacheSize; ++i) {
323 cache[i]->decRefCnt();
328 CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
332 if (cache[0] && cache[0]->match(collection, cMapName)) {
333 cache[0]->incRefCnt();
336 for (i = 1; i < cMapCacheSize; ++i) {
337 if (cache[i] && cache[i]->match(collection, cMapName)) {
339 for (j = i; j >= 1; --j) {
340 cache[j] = cache[j - 1];
347 if ((cmap = CMap::parse(this, collection, cMapName))) {
348 if (cache[cMapCacheSize - 1]) {
349 cache[cMapCacheSize - 1]->decRefCnt();
351 for (j = cMapCacheSize - 1; j >= 1; --j) {
352 cache[j] = cache[j - 1];