00001
00002
00003
00004
00005
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
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
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 }