Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CMap.cc

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

Generated on Sat Nov 5 16:18:13 2005 for OPIE by  doxygen 1.4.2