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