CharCodeToUnicode.cpp
1//========================================================================
2//
3// CharCodeToUnicode.cpp
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
29struct CharCodeToUnicodeString {
30 CharCode c;
31 Unicode u[maxUnicodeString];
32 int len;
33};
34
35//------------------------------------------------------------------------
36
37static 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
51static int getCharFromFile(void *data) {
52 return fgetc((FILE *)data);
53}
54
55//------------------------------------------------------------------------
56
57CharCodeToUnicode *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
97CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
98 return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0);
99}
100
101CharCodeToUnicode *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
111void 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
265CharCodeToUnicode::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
279CharCodeToUnicode::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
296CharCodeToUnicode::~CharCodeToUnicode() {
297 if (collection) {
298 delete collection;
299 }
300 gfree(map);
301 if (sMap) {
302 gfree(sMap);
303 }
304}
305
306void CharCodeToUnicode::incRefCnt() {
307 ++refCnt;
308}
309
310void CharCodeToUnicode::decRefCnt() {
311 if (--refCnt == 0) {
312 delete this;
313 }
314}
315
316GBool CharCodeToUnicode::match(GString *collectionA) {
317 return collection && !collection->cmp(collectionA);
318}
319
320int 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
343CIDToUnicodeCache::CIDToUnicodeCache() {
344 int i;
345
346 for (i = 0; i < cidToUnicodeCacheSize; ++i) {
347 cache[i] = NULL;
348 }
349}
350
351CIDToUnicodeCache::~CIDToUnicodeCache() {
352 int i;
353
354 for (i = 0; i < cidToUnicodeCacheSize; ++i) {
355 if (cache[i]) {
356 cache[i]->decRefCnt();
357 }
358 }
359}
360
361CharCodeToUnicode *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}