filters

CMap.cc

00001 //========================================================================
00002 //
00003 // CMap.cc
00004 //
00005 // Copyright 2001-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 #include "gmem.h"
00020 #include "gfile.h"
00021 #include "GString.h"
00022 #include "Error.h"
00023 #include "GlobalParams.h"
00024 #include "PSTokenizer.h"
00025 #include "CMap.h"
00026 
00027 //------------------------------------------------------------------------
00028 
00029 struct CMapVectorEntry {
00030   GBool isVector;
00031   union {
00032     CMapVectorEntry *vector;
00033     CID cid;
00034   };
00035 };
00036 
00037 //------------------------------------------------------------------------
00038 
00039 static int getCharFromFile(void *data) {
00040   return fgetc((FILE *)data);
00041 }
00042 
00043 //------------------------------------------------------------------------
00044 
00045 CMap *CMap::parse(CMapCache *cache, GString *collectionA,
00046           GString *cMapNameA) {
00047   FILE *f;
00048   CMap *cmap;
00049   PSTokenizer *pst;
00050   char tok1[256], tok2[256], tok3[256];
00051   int n1, n2, n3;
00052   Guint start, end;
00053 
00054   if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
00055 
00056     // Check for an identity CMap.
00057     if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
00058       return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
00059     }
00060     if (!cMapNameA->cmp("Identity-V")) {
00061       return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
00062     }
00063 
00064     error(-1, "Couldn't find '%s' CMap file for '%s' collection",
00065       cMapNameA->getCString(), collectionA->getCString());
00066     return NULL;
00067   }
00068 
00069   cmap = new CMap(collectionA->copy(), cMapNameA->copy());
00070 
00071   pst = new PSTokenizer(&getCharFromFile, f);
00072   pst->getToken(tok1, sizeof(tok1), &n1);
00073   while (pst->getToken(tok2, sizeof(tok2), &n2)) {
00074     if (!strcmp(tok2, "usecmap")) {
00075       if (tok1[0] == '/') {
00076     cmap->useCMap(cache, tok1 + 1);
00077       }
00078       pst->getToken(tok1, sizeof(tok1), &n1);
00079     } else if (!strcmp(tok1, "/WMode")) {
00080       cmap->wMode = atoi(tok2);
00081       pst->getToken(tok1, sizeof(tok1), &n1);
00082     } else if (!strcmp(tok2, "begincodespacerange")) {
00083       while (pst->getToken(tok1, sizeof(tok1), &n1)) {
00084     if (!strcmp(tok1, "endcodespacerange")) {
00085       break;
00086     }
00087     if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
00088         !strcmp(tok2, "endcodespacerange")) {
00089       error(-1, "Illegal entry in codespacerange block in CMap");
00090       break;
00091     }
00092     if (tok1[0] == '<' && tok2[0] == '<' &&
00093         n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
00094       tok1[n1 - 1] = tok2[n1 - 1] = '\0';
00095       sscanf(tok1 + 1, "%x", &start);
00096       sscanf(tok2 + 1, "%x", &end);
00097       n1 = (n1 - 2) / 2;
00098       cmap->addCodeSpace(cmap->vector, start, end, n1);
00099     }
00100       }
00101       pst->getToken(tok1, sizeof(tok1), &n1);
00102     } else if (!strcmp(tok2, "begincidrange")) {
00103       while (pst->getToken(tok1, sizeof(tok1), &n1)) {
00104     if (!strcmp(tok1, "endcidrange")) {
00105       break;
00106     }
00107     if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
00108         !strcmp(tok2, "endcidrange") ||
00109         !pst->getToken(tok3, sizeof(tok3), &n3) ||
00110         !strcmp(tok3, "endcidrange")) {
00111       error(-1, "Illegal entry in cidrange block in CMap");
00112       break;
00113     }
00114     if (tok1[0] == '<' && tok2[0] == '<' &&
00115         n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
00116       tok1[n1 - 1] = tok2[n1 - 1] = '\0';
00117       sscanf(tok1 + 1, "%x", &start);
00118       sscanf(tok2 + 1, "%x", &end);
00119       n1 = (n1 - 2) / 2;
00120       cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
00121     }
00122       }
00123       pst->getToken(tok1, sizeof(tok1), &n1);
00124     } else {
00125       strcpy(tok1, tok2);
00126     }
00127   }
00128   delete pst;
00129 
00130   fclose(f);
00131 
00132   return cmap;
00133 }
00134 
00135 CMap::CMap(GString *collectionA, GString *cMapNameA) {
00136   int i;
00137 
00138   collection = collectionA;
00139   cMapName = cMapNameA;
00140   wMode = 0;
00141   vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
00142   for (i = 0; i < 256; ++i) {
00143     vector[i].isVector = gFalse;
00144     vector[i].cid = 0;
00145   }
00146   refCnt = 1;
00147 }
00148 
00149 CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
00150   collection = collectionA;
00151   cMapName = cMapNameA;
00152   wMode = wModeA;
00153   vector = NULL;
00154   refCnt = 1;
00155 }
00156 
00157 void CMap::useCMap(CMapCache *cache, char *useName) {
00158   GString *useNameStr;
00159   CMap *subCMap;
00160 
00161   useNameStr = new GString(useName);
00162   subCMap = cache->getCMap(collection, useNameStr);
00163   delete useNameStr;
00164   if (!subCMap) {
00165     return;
00166   }
00167   copyVector(vector, subCMap->vector);
00168   subCMap->decRefCnt();
00169 }
00170 
00171 void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
00172   int i, j;
00173 
00174   for (i = 0; i < 256; ++i) {
00175     if (src[i].isVector) {
00176       if (!dest[i].isVector) {
00177     dest[i].isVector = gTrue;
00178     dest[i].vector =
00179       (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
00180     for (j = 0; j < 256; ++j) {
00181       dest[i].vector[j].isVector = gFalse;
00182       dest[i].vector[j].cid = 0;
00183     }
00184       }
00185       copyVector(dest[i].vector, src[i].vector);
00186     } else {
00187       if (dest[i].isVector) {
00188     error(-1, "Collision in usecmap");
00189       } else {
00190     dest[i].cid = src[i].cid;
00191       }
00192     }
00193   }
00194 }
00195 
00196 void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
00197             Guint nBytes) {
00198   Guint start2, end2;
00199   int startByte, endByte, i, j;
00200 
00201   if (nBytes > 1) {
00202     startByte = (start >> (8 * (nBytes - 1))) & 0xff;
00203     endByte = (end >> (8 * (nBytes - 1))) & 0xff;
00204     start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
00205     end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
00206     for (i = startByte; i <= endByte; ++i) {
00207       if (!vec[i].isVector) {
00208     vec[i].isVector = gTrue;
00209     vec[i].vector =
00210       (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
00211     for (j = 0; j < 256; ++j) {
00212       vec[i].vector[j].isVector = gFalse;
00213       vec[i].vector[j].cid = 0;
00214     }
00215       }
00216       addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
00217     }
00218   }
00219 }
00220 
00221 void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
00222   CMapVectorEntry *vec;
00223   CID cid;
00224   int byte;
00225   Guint i;
00226 
00227   vec = vector;
00228   for (i = nBytes - 1; i >= 1; --i) {
00229     byte = (start >> (8 * i)) & 0xff;
00230     if (!vec[byte].isVector) {
00231       error(-1, "Invalid CID (%*x - %*x) in CMap",
00232         2*nBytes, start, 2*nBytes, end);
00233       return;
00234     }
00235     vec = vec[byte].vector;
00236   }
00237   cid = firstCID;
00238   for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
00239     if (vec[byte].isVector) {
00240       error(-1, "Invalid CID (%*x - %*x) in CMap",
00241         2*nBytes, start, 2*nBytes, end);
00242     } else {
00243       vec[byte].cid = cid;
00244     }
00245     ++cid;
00246   }
00247 }
00248 
00249 CMap::~CMap() {
00250   delete collection;
00251   delete cMapName;
00252   if (vector) {
00253     freeCMapVector(vector);
00254   }
00255 }
00256 
00257 void CMap::freeCMapVector(CMapVectorEntry *vec) {
00258   int i;
00259 
00260   for (i = 0; i < 256; ++i) {
00261     if (vec[i].isVector) {
00262       freeCMapVector(vec[i].vector);
00263     }
00264   }
00265   gfree(vec);
00266 }
00267 
00268 void CMap::incRefCnt() {
00269   ++refCnt;
00270 }
00271 
00272 void CMap::decRefCnt() {
00273   if (--refCnt == 0) {
00274     delete this;
00275   }
00276 }
00277 
00278 GBool CMap::match(GString *collectionA, GString *cMapNameA) {
00279   return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
00280 }
00281 
00282 CID CMap::getCID(char *s, int len, int *nUsed) {
00283   CMapVectorEntry *vec;
00284   int n, i;
00285 
00286   if (!(vec = vector)) {
00287     // identity CMap
00288     *nUsed = 2;
00289     if (len < 2) {
00290       return 0;
00291     }
00292     return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
00293   }
00294   n = 0;
00295   while (1) {
00296     if (n >= len) {
00297       *nUsed = n;
00298       return 0;
00299     }
00300     i = s[n++] & 0xff;
00301     if (!vec[i].isVector) {
00302       *nUsed = n;
00303       return vec[i].cid;
00304     }
00305     vec = vec[i].vector;
00306   }
00307 }
00308 
00309 //------------------------------------------------------------------------
00310 
00311 CMapCache::CMapCache() {
00312   int i;
00313 
00314   for (i = 0; i < cMapCacheSize; ++i) {
00315     cache[i] = NULL;
00316   }
00317 }
00318 
00319 CMapCache::~CMapCache() {
00320   int i;
00321 
00322   for (i = 0; i < cMapCacheSize; ++i) {
00323     if (cache[i]) {
00324       cache[i]->decRefCnt();
00325     }
00326   }
00327 }
00328 
00329 CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
00330   CMap *cmap;
00331   int i, j;
00332 
00333   if (cache[0] && cache[0]->match(collection, cMapName)) {
00334     cache[0]->incRefCnt();
00335     return cache[0];
00336   }
00337   for (i = 1; i < cMapCacheSize; ++i) {
00338     if (cache[i] && cache[i]->match(collection, cMapName)) {
00339       cmap = cache[i];
00340       for (j = i; j >= 1; --j) {
00341     cache[j] = cache[j - 1];
00342       }
00343       cache[0] = cmap;
00344       cmap->incRefCnt();
00345       return cmap;
00346     }
00347   }
00348   if ((cmap = CMap::parse(this, collection, cMapName))) {
00349     if (cache[cMapCacheSize - 1]) {
00350       cache[cMapCacheSize - 1]->decRefCnt();
00351     }
00352     for (j = cMapCacheSize - 1; j >= 1; --j) {
00353       cache[j] = cache[j - 1];
00354     }
00355     cache[0] = cmap;
00356     cmap->incRefCnt();
00357     return cmap;
00358   }
00359   return NULL;
00360 }
KDE Home | KDE Accessibility Home | Description of Access Keys