Back to index

tetex-bin  3.0
CMap.cc
Go to the documentation of this file.
00001 //========================================================================
00002 //
00003 // CMap.cc
00004 //
00005 // Copyright 2001-2003 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 #if MULTITHREADED
00148   gInitMutex(&mutex);
00149 #endif
00150 }
00151 
00152 CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
00153   collection = collectionA;
00154   cMapName = cMapNameA;
00155   wMode = wModeA;
00156   vector = NULL;
00157   refCnt = 1;
00158 #if MULTITHREADED
00159   gInitMutex(&mutex);
00160 #endif
00161 }
00162 
00163 void CMap::useCMap(CMapCache *cache, char *useName) {
00164   GString *useNameStr;
00165   CMap *subCMap;
00166 
00167   useNameStr = new GString(useName);
00168   subCMap = cache->getCMap(collection, useNameStr);
00169   delete useNameStr;
00170   if (!subCMap) {
00171     return;
00172   }
00173   copyVector(vector, subCMap->vector);
00174   subCMap->decRefCnt();
00175 }
00176 
00177 void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
00178   int i, j;
00179 
00180   for (i = 0; i < 256; ++i) {
00181     if (src[i].isVector) {
00182       if (!dest[i].isVector) {
00183        dest[i].isVector = gTrue;
00184        dest[i].vector =
00185          (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
00186        for (j = 0; j < 256; ++j) {
00187          dest[i].vector[j].isVector = gFalse;
00188          dest[i].vector[j].cid = 0;
00189        }
00190       }
00191       copyVector(dest[i].vector, src[i].vector);
00192     } else {
00193       if (dest[i].isVector) {
00194        error(-1, "Collision in usecmap");
00195       } else {
00196        dest[i].cid = src[i].cid;
00197       }
00198     }
00199   }
00200 }
00201 
00202 void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
00203                      Guint nBytes) {
00204   Guint start2, end2;
00205   int startByte, endByte, i, j;
00206 
00207   if (nBytes > 1) {
00208     startByte = (start >> (8 * (nBytes - 1))) & 0xff;
00209     endByte = (end >> (8 * (nBytes - 1))) & 0xff;
00210     start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
00211     end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
00212     for (i = startByte; i <= endByte; ++i) {
00213       if (!vec[i].isVector) {
00214        vec[i].isVector = gTrue;
00215        vec[i].vector =
00216          (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
00217        for (j = 0; j < 256; ++j) {
00218          vec[i].vector[j].isVector = gFalse;
00219          vec[i].vector[j].cid = 0;
00220        }
00221       }
00222       addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
00223     }
00224   }
00225 }
00226 
00227 void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
00228   CMapVectorEntry *vec;
00229   CID cid;
00230   int byte;
00231   Guint i;
00232 
00233   vec = vector;
00234   for (i = nBytes - 1; i >= 1; --i) {
00235     byte = (start >> (8 * i)) & 0xff;
00236     if (!vec[byte].isVector) {
00237       error(-1, "Invalid CID (%*x - %*x) in CMap",
00238            2*nBytes, start, 2*nBytes, end);
00239       return;
00240     }
00241     vec = vec[byte].vector;
00242   }
00243   cid = firstCID;
00244   for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
00245     if (vec[byte].isVector) {
00246       error(-1, "Invalid CID (%*x - %*x) in CMap",
00247            2*nBytes, start, 2*nBytes, end);
00248     } else {
00249       vec[byte].cid = cid;
00250     }
00251     ++cid;
00252   }
00253 }
00254 
00255 CMap::~CMap() {
00256   delete collection;
00257   delete cMapName;
00258   if (vector) {
00259     freeCMapVector(vector);
00260   }
00261 #if MULTITHREADED
00262   gDestroyMutex(&mutex);
00263 #endif
00264 }
00265 
00266 void CMap::freeCMapVector(CMapVectorEntry *vec) {
00267   int i;
00268 
00269   for (i = 0; i < 256; ++i) {
00270     if (vec[i].isVector) {
00271       freeCMapVector(vec[i].vector);
00272     }
00273   }
00274   gfree(vec);
00275 }
00276 
00277 void CMap::incRefCnt() {
00278 #if MULTITHREADED
00279   gLockMutex(&mutex);
00280 #endif
00281   ++refCnt;
00282 #if MULTITHREADED
00283   gUnlockMutex(&mutex);
00284 #endif
00285 }
00286 
00287 void CMap::decRefCnt() {
00288   GBool done;
00289 
00290 #if MULTITHREADED
00291   gLockMutex(&mutex);
00292 #endif
00293   done = --refCnt == 0;
00294 #if MULTITHREADED
00295   gUnlockMutex(&mutex);
00296 #endif
00297   if (done) {
00298     delete this;
00299   }
00300 }
00301 
00302 GBool CMap::match(GString *collectionA, GString *cMapNameA) {
00303   return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
00304 }
00305 
00306 CID CMap::getCID(char *s, int len, int *nUsed) {
00307   CMapVectorEntry *vec;
00308   int n, i;
00309 
00310   if (!(vec = vector)) {
00311     // identity CMap
00312     *nUsed = 2;
00313     if (len < 2) {
00314       return 0;
00315     }
00316     return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
00317   }
00318   n = 0;
00319   while (1) {
00320     if (n >= len) {
00321       *nUsed = n;
00322       return 0;
00323     }
00324     i = s[n++] & 0xff;
00325     if (!vec[i].isVector) {
00326       *nUsed = n;
00327       return vec[i].cid;
00328     }
00329     vec = vec[i].vector;
00330   }
00331 }
00332 
00333 //------------------------------------------------------------------------
00334 
00335 CMapCache::CMapCache() {
00336   int i;
00337 
00338   for (i = 0; i < cMapCacheSize; ++i) {
00339     cache[i] = NULL;
00340   }
00341 }
00342 
00343 CMapCache::~CMapCache() {
00344   int i;
00345 
00346   for (i = 0; i < cMapCacheSize; ++i) {
00347     if (cache[i]) {
00348       cache[i]->decRefCnt();
00349     }
00350   }
00351 }
00352 
00353 CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
00354   CMap *cmap;
00355   int i, j;
00356 
00357   if (cache[0] && cache[0]->match(collection, cMapName)) {
00358     cache[0]->incRefCnt();
00359     return cache[0];
00360   }
00361   for (i = 1; i < cMapCacheSize; ++i) {
00362     if (cache[i] && cache[i]->match(collection, cMapName)) {
00363       cmap = cache[i];
00364       for (j = i; j >= 1; --j) {
00365        cache[j] = cache[j - 1];
00366       }
00367       cache[0] = cmap;
00368       cmap->incRefCnt();
00369       return cmap;
00370     }
00371   }
00372   if ((cmap = CMap::parse(this, collection, cMapName))) {
00373     if (cache[cMapCacheSize - 1]) {
00374       cache[cMapCacheSize - 1]->decRefCnt();
00375     }
00376     for (j = cMapCacheSize - 1; j >= 1; --j) {
00377       cache[j] = cache[j - 1];
00378     }
00379     cache[0] = cmap;
00380     cmap->incRefCnt();
00381     return cmap;
00382   }
00383   return NULL;
00384 }