]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/CharCodeToUnicode.cc
Import of Xpdf 2.00 for merge
[evince.git] / pdf / xpdf / CharCodeToUnicode.cc
1 //========================================================================
2 //
3 // CharCodeToUnicode.cc
4 //
5 // Copyright 2001-2002 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <stdio.h>
16 #include <string.h>
17 #include "gmem.h"
18 #include "gfile.h"
19 #include "GString.h"
20 #include "Error.h"
21 #include "GlobalParams.h"
22 #include "PSTokenizer.h"
23 #include "CharCodeToUnicode.h"
24
25 //------------------------------------------------------------------------
26
27 #define maxUnicodeString 8
28
29 struct CharCodeToUnicodeString {
30   CharCode c;
31   Unicode u[maxUnicodeString];
32   int len;
33 };
34
35 //------------------------------------------------------------------------
36
37 static int getCharFromString(void *data) {
38   char *p;
39   int c;
40
41   p = *(char **)data;
42   if (*p) {
43     c = *p++;
44     *(char **)data = p;
45   } else {
46     c = EOF;
47   }
48   return c;
49 }
50
51 static int getCharFromFile(void *data) {
52   return fgetc((FILE *)data);
53 }
54
55 //------------------------------------------------------------------------
56
57 CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) {
58   FILE *f;
59   Unicode *mapA;
60   CharCode size, mapLenA;
61   char buf[64];
62   Unicode u;
63   CharCodeToUnicode *ctu;
64
65   if (!(f = globalParams->getCIDToUnicodeFile(collectionA))) {
66     error(-1, "Couldn't find cidToUnicode file for the '%s' collection",
67           collectionA->getCString());
68     return NULL;
69   }
70
71   size = 32768;
72   mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
73   mapLenA = 0;
74
75   while (getLine(buf, sizeof(buf), f)) {
76     if (mapLenA == size) {
77       size *= 2;
78       mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
79     }
80     if (sscanf(buf, "%x", &u) == 1) {
81       mapA[mapLenA] = u;
82     } else {
83       error(-1, "Bad line (%d) in cidToUnicode file for the '%s' collection",
84             (int)(mapLenA + 1), collectionA->getCString());
85       mapA[mapLenA] = 0;
86     }
87     ++mapLenA;
88   }
89   fclose(f);
90
91   ctu = new CharCodeToUnicode(collectionA->copy(), mapA, mapLenA, gTrue,
92                               NULL, 0);
93   gfree(mapA);
94   return ctu;
95 }
96
97 CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
98   return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0);
99 }
100
101 CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) {
102   CharCodeToUnicode *ctu;
103   char *p;
104
105   ctu = new CharCodeToUnicode(NULL);
106   p = buf->getCString();
107   ctu->parseCMap1(&getCharFromString, &p, nBits);
108   return ctu;
109 }
110
111 void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
112                                    int nBits) {
113   PSTokenizer *pst;
114   char tok1[256], tok2[256], tok3[256];
115   int nDigits, n1, n2, n3;
116   CharCode oldLen, i;
117   CharCode code1, code2;
118   Unicode u;
119   char uHex[5];
120   int j;
121   GString *name;
122   FILE *f;
123
124   nDigits = nBits / 4;
125   pst = new PSTokenizer(getCharFunc, data);
126   pst->getToken(tok1, sizeof(tok1), &n1);
127   while (pst->getToken(tok2, sizeof(tok2), &n2)) {
128     if (!strcmp(tok2, "usecmap")) {
129       if (tok1[0] == '/') {
130         name = new GString(tok1 + 1);
131         if ((f = globalParams->findToUnicodeFile(name))) {
132           parseCMap1(&getCharFromFile, f, nBits);
133           fclose(f);
134         } else {
135           error(-1, "Couldn't find ToUnicode CMap file for '%s'",
136                 name->getCString());
137         }
138         delete name;
139       }
140       pst->getToken(tok1, sizeof(tok1), &n1);
141     } else if (!strcmp(tok2, "beginbfchar")) {
142       while (pst->getToken(tok1, sizeof(tok1), &n1)) {
143         if (!strcmp(tok1, "endbfchar")) {
144           break;
145         }
146         if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
147             !strcmp(tok2, "endbfchar")) {
148           error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
149           break;
150         }
151         if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
152               tok2[0] == '<' && tok2[n2 - 1] == '>')) {
153           error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
154           continue;
155         }
156         tok1[n1 - 1] = tok2[n2 - 1] = '\0';
157         if (sscanf(tok1 + 1, "%x", &code1) != 1) {
158           error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
159           continue;
160         }
161         if (code1 >= mapLen) {
162           oldLen = mapLen;
163           mapLen = (code1 + 256) & ~255;
164           map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
165           for (i = oldLen; i < mapLen; ++i) {
166             map[i] = 0;
167           }
168         }
169         if (n2 == 6) {
170           if (sscanf(tok2 + 1, "%x", &u) != 1) {
171             error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
172             continue;
173           }
174           map[code1] = u;
175         } else {
176           map[code1] = 0;
177           if (sMapLen == sMapSize) {
178             sMapSize += 8;
179             sMap = (CharCodeToUnicodeString *)
180                 grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
181           }
182           sMap[sMapLen].c = code1;
183           sMap[sMapLen].len = (n2 - 2) / 4;
184           for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
185             strncpy(uHex, tok2 + 1 + j*4, 4);
186             uHex[4] = '\0';
187             if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
188               error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
189             }
190           }
191           ++sMapLen;
192         }
193       }
194       pst->getToken(tok1, sizeof(tok1), &n1);
195     } else if (!strcmp(tok2, "beginbfrange")) {
196       while (pst->getToken(tok1, sizeof(tok1), &n1)) {
197         if (!strcmp(tok1, "endbfrange")) {
198           break;
199         }
200         if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
201             !strcmp(tok2, "endbfrange") ||
202             !pst->getToken(tok3, sizeof(tok3), &n3) ||
203             !strcmp(tok3, "endbfrange")) {
204           error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
205           break;
206         }
207         if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
208               n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>' &&
209               tok3[0] == '<' && tok3[n3 - 1] == '>')) {
210           error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
211           continue;
212         }
213         tok1[n1 - 1] = tok2[n2 - 1] = tok3[n3 - 1] = '\0';
214         if (sscanf(tok1 + 1, "%x", &code1) != 1 ||
215             sscanf(tok2 + 1, "%x", &code2) != 1) {
216           error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
217           continue;
218         }
219         if (code2 >= mapLen) {
220           oldLen = mapLen;
221           mapLen = (code2 + 256) & ~255;
222           map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
223           for (i = oldLen; i < mapLen; ++i) {
224             map[i] = 0;
225           }
226         }
227         if (n3 == 6) {
228           if (sscanf(tok3 + 1, "%x", &u) != 1) {
229             error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
230             continue;
231           }
232           for (; code1 <= code2; ++code1) {
233             map[code1] = u++;
234           }
235         } else {
236           if (sMapLen + (int)(code2 - code1 + 1) > sMapSize) {
237             sMapSize = (sMapSize + (code2 - code1 + 1) + 7) & ~7;
238             sMap = (CharCodeToUnicodeString *)
239                 grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
240           }
241           for (i = 0; code1 <= code2; ++code1, ++i) {
242             map[code1] = 0;
243             sMap[sMapLen].c = code1;
244             sMap[sMapLen].len = (n3 - 2) / 4;
245             for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
246               strncpy(uHex, tok3 + 1 + j*4, 4);
247               uHex[4] = '\0';
248               if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
249                 error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
250               }
251             }
252             sMap[sMapLen].u[sMap[sMapLen].len - 1] += i;
253             ++sMapLen;
254           }
255         }
256       }
257       pst->getToken(tok1, sizeof(tok1), &n1);
258     } else {
259       strcpy(tok1, tok2);
260     }
261   }
262   delete pst;
263 }
264
265 CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) {
266   CharCode i;
267
268   collection = collectionA;
269   mapLen = 256;
270   map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
271   for (i = 0; i < mapLen; ++i) {
272     map[i] = 0;
273   }
274   sMap = NULL;
275   sMapLen = sMapSize = 0;
276   refCnt = 1;
277 }
278
279 CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA,
280                                      CharCode mapLenA, GBool copyMap,
281                                      CharCodeToUnicodeString *sMapA,
282                                      int sMapLenA) {
283   collection = collectionA;
284   mapLen = mapLenA;
285   if (copyMap) {
286     map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
287     memcpy(map, mapA, mapLen * sizeof(Unicode));
288   } else {
289     map = mapA;
290   }
291   sMap = sMapA;
292   sMapLen = sMapSize = sMapLenA;
293   refCnt = 1;
294 }
295
296 CharCodeToUnicode::~CharCodeToUnicode() {
297   if (collection) {
298     delete collection;
299   }
300   gfree(map);
301   if (sMap) {
302     gfree(sMap);
303   }
304 }
305
306 void CharCodeToUnicode::incRefCnt() {
307   ++refCnt;
308 }
309
310 void CharCodeToUnicode::decRefCnt() {
311   if (--refCnt == 0) {
312     delete this;
313   }
314 }
315
316 GBool CharCodeToUnicode::match(GString *collectionA) {
317   return collection && !collection->cmp(collectionA);
318 }
319
320 int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) {
321   int i, j;
322
323   if (c >= mapLen) {
324     return 0;
325   }
326   if (map[c]) {
327     u[0] = map[c];
328     return 1;
329   }
330   for (i = 0; i < sMapLen; ++i) {
331     if (sMap[i].c == c) {
332       for (j = 0; j < sMap[i].len && j < size; ++j) {
333         u[j] = sMap[i].u[j];
334       }
335       return j;
336     }
337   }
338   return 0;
339 }
340
341 //------------------------------------------------------------------------
342
343 CIDToUnicodeCache::CIDToUnicodeCache() {
344   int i;
345
346   for (i = 0; i < cidToUnicodeCacheSize; ++i) {
347     cache[i] = NULL;
348   }
349 }
350
351 CIDToUnicodeCache::~CIDToUnicodeCache() {
352   int i;
353
354   for (i = 0; i < cidToUnicodeCacheSize; ++i) {
355     if (cache[i]) {
356       cache[i]->decRefCnt();
357     }
358   }
359 }
360
361 CharCodeToUnicode *CIDToUnicodeCache::getCIDToUnicode(GString *collection) {
362   CharCodeToUnicode *ctu;
363   int i, j;
364
365   if (cache[0] && cache[0]->match(collection)) {
366     cache[0]->incRefCnt();
367     return cache[0];
368   }
369   for (i = 1; i < cidToUnicodeCacheSize; ++i) {
370     if (cache[i] && cache[i]->match(collection)) {
371       ctu = cache[i];
372       for (j = i; j >= 1; --j) {
373         cache[j] = cache[j - 1];
374       }
375       cache[0] = ctu;
376       ctu->incRefCnt();
377       return ctu;
378     }
379   }
380   if ((ctu = CharCodeToUnicode::parseCIDToUnicode(collection))) {
381     if (cache[cidToUnicodeCacheSize - 1]) {
382       cache[cidToUnicodeCacheSize - 1]->decRefCnt();
383     }
384     for (j = cidToUnicodeCacheSize - 1; j >= 1; --j) {
385       cache[j] = cache[j - 1];
386     }
387     cache[0] = ctu;
388     ctu->incRefCnt();
389     return ctu;
390   }
391   return NULL;
392 }