summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/CMap.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/CMap.cc') (more/less context) (show whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/CMap.cc339
1 files changed, 339 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/CMap.cc b/noncore/unsupported/qpdf/xpdf/CMap.cc
new file mode 100644
index 0000000..57809f0
--- a/dev/null
+++ b/noncore/unsupported/qpdf/xpdf/CMap.cc
@@ -0,0 +1,339 @@
1//========================================================================
2//
3// CMap.cc
4//
5// Copyright 2001 Derek B. Noonburg
6//
7//========================================================================
8
9#ifdef __GNUC__
10#pragma implementation
11#endif
12
13#include <aconf.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h>
18#include "gmem.h"
19#include "gfile.h"
20#include "GString.h"
21#include "Error.h"
22#include "GlobalParams.h"
23#include "CMap.h"
24
25//------------------------------------------------------------------------
26
27struct CMapVectorEntry {
28 GBool isVector;
29 union {
30 CMapVectorEntry *vector;
31 CID cid;
32 };
33};
34
35//------------------------------------------------------------------------
36
37CMap *CMap::parse(CMapCache *cache, GString *collectionA,
38 GString *cMapNameA) {
39 FILE *f;
40 CMap *cmap;
41 char buf[256];
42 GBool inCodeSpace, inCIDRange;
43 char *tok1, *tok2, *tok3;
44 Guint start, end;
45 Guint n;
46
47 if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
48
49 // Check for an identity CMap.
50 if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
51 return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
52 }
53 if (!cMapNameA->cmp("Identity-V")) {
54 return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
55 }
56
57 error(-1, "Couldn't find '%s' CMap file for '%s' collection",
58 cMapNameA->getCString(), collectionA->getCString());
59 return NULL;
60 }
61
62 cmap = new CMap(collectionA->copy(), cMapNameA->copy());
63
64 inCodeSpace = inCIDRange = gFalse;
65 while (getLine(buf, sizeof(buf), f)) {
66 tok1 = strtok(buf, " \t\r\n");
67 if (!tok1 || tok1[0] == '%') {
68 continue;
69 }
70 tok2 = strtok(NULL, " \t\r\n");
71 tok3 = strtok(NULL, " \t\r\n");
72 if (inCodeSpace) {
73 if (!strcmp(tok1, "endcodespacerange")) {
74 inCodeSpace = gFalse;
75 } else if (tok2 && tok1[0] == '<' && tok2[0] == '<' &&
76 (n = strlen(tok1)) == strlen(tok2) &&
77 n >= 4 && (n & 1) == 0) {
78 tok1[n - 1] = tok2[n - 1] = '\0';
79 sscanf(tok1 + 1, "%x", &start);
80 sscanf(tok2 + 1, "%x", &end);
81 n = (n - 2) / 2;
82 cmap->addCodeSpace(cmap->vector, start, end, n);
83 }
84 } else if (inCIDRange) {
85 if (!strcmp(tok1, "endcidrange")) {
86 inCIDRange = gFalse;
87 } else if (tok2 && tok3 && tok1[0] == '<' && tok2[0] == '<' &&
88 (n = strlen(tok1)) == strlen(tok2) &&
89 n >= 4 && (n & 1) == 0) {
90 tok1[n - 1] = tok2[n - 1] = '\0';
91 sscanf(tok1 + 1, "%x", &start);
92 sscanf(tok2 + 1, "%x", &end);
93 n = (n - 2) / 2;
94 cmap->addCIDs(start, end, n, (CID)atoi(tok3));
95 }
96 } else if (tok2 && !strcmp(tok2, "usecmap")) {
97 if (tok1[0] == '/') {
98 cmap->useCMap(cache, tok1 + 1);
99 }
100 } else if (!strcmp(tok1, "/WMode")) {
101 cmap->wMode = atoi(tok2);
102 } else if (tok2 && !strcmp(tok2, "begincodespacerange")) {
103 inCodeSpace = gTrue;
104 } else if (tok2 && !strcmp(tok2, "begincidrange")) {
105 inCIDRange = gTrue;
106 }
107 }
108
109 fclose(f);
110
111 return cmap;
112}
113
114CMap::CMap(GString *collectionA, GString *cMapNameA) {
115 int i;
116
117 collection = collectionA;
118 cMapName = cMapNameA;
119 wMode = 0;
120 vector = (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
121 for (i = 0; i < 256; ++i) {
122 vector[i].isVector = gFalse;
123 vector[i].cid = 0;
124 }
125 refCnt = 1;
126}
127
128CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
129 collection = collectionA;
130 cMapName = cMapNameA;
131 wMode = wModeA;
132 vector = NULL;
133 refCnt = 1;
134}
135
136void CMap::useCMap(CMapCache *cache, char *useName) {
137 GString *useNameStr;
138 CMap *subCMap;
139
140 useNameStr = new GString(useName);
141 subCMap = cache->getCMap(collection, useNameStr);
142 delete useNameStr;
143 if (!subCMap) {
144 return;
145 }
146 copyVector(vector, subCMap->vector);
147 subCMap->decRefCnt();
148}
149
150void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
151 int i, j;
152
153 for (i = 0; i < 256; ++i) {
154 if (src[i].isVector) {
155 if (!dest[i].isVector) {
156 dest[i].isVector = gTrue;
157 dest[i].vector =
158 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
159 for (j = 0; j < 256; ++j) {
160 dest[i].vector[j].isVector = gFalse;
161 dest[i].vector[j].cid = 0;
162 }
163 }
164 copyVector(dest[i].vector, src[i].vector);
165 } else {
166 if (dest[i].isVector) {
167 error(-1, "Collision in usecmap");
168 } else {
169 dest[i].cid = src[i].cid;
170 }
171 }
172 }
173}
174
175void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
176 Guint nBytes) {
177 Guint start2, end2;
178 int startByte, endByte, i, j;
179
180 if (nBytes > 1) {
181 startByte = (start >> (8 * (nBytes - 1))) & 0xff;
182 endByte = (end >> (8 * (nBytes - 1))) & 0xff;
183 start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
184 end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
185 for (i = startByte; i <= endByte; ++i) {
186 if (!vec[i].isVector) {
187 vec[i].isVector = gTrue;
188 vec[i].vector =
189 (CMapVectorEntry *)gmalloc(256 * sizeof(CMapVectorEntry));
190 for (j = 0; j < 256; ++j) {
191 vec[i].vector[j].isVector = gFalse;
192 vec[i].vector[j].cid = 0;
193 }
194 }
195 addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
196 }
197 }
198}
199
200void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
201 CMapVectorEntry *vec;
202 CID cid;
203 int byte;
204 Guint i;
205
206 vec = vector;
207 for (i = nBytes - 1; i >= 1; --i) {
208 byte = (start >> (8 * i)) & 0xff;
209 if (!vec[byte].isVector) {
210 error(-1, "Invalid CID (%*x - %*x) in CMap",
211 2*nBytes, start, 2*nBytes, end);
212 return;
213 }
214 vec = vec[byte].vector;
215 }
216 cid = firstCID;
217 for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
218 if (vec[byte].isVector) {
219 error(-1, "Invalid CID (%*x - %*x) in CMap",
220 2*nBytes, start, 2*nBytes, end);
221 } else {
222 vec[byte].cid = cid;
223 }
224 ++cid;
225 }
226}
227
228CMap::~CMap() {
229 delete collection;
230 delete cMapName;
231 if (vector) {
232 freeCMapVector(vector);
233 }
234}
235
236void CMap::freeCMapVector(CMapVectorEntry *vec) {
237 int i;
238
239 for (i = 0; i < 256; ++i) {
240 if (vec[i].isVector) {
241 freeCMapVector(vec[i].vector);
242 }
243 }
244 gfree(vec);
245}
246
247void CMap::incRefCnt() {
248 ++refCnt;
249}
250
251void CMap::decRefCnt() {
252 if (--refCnt == 0) {
253 delete this;
254 }
255}
256
257GBool CMap::match(GString *collectionA, GString *cMapNameA) {
258 return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
259}
260
261CID CMap::getCID(char *s, int len, int *nUsed) {
262 CMapVectorEntry *vec;
263 int n, i;
264
265 if (!(vec = vector)) {
266 // identity CMap
267 *nUsed = 2;
268 if (len < 2) {
269 return 0;
270 }
271 return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
272 }
273 n = 0;
274 while (1) {
275 if (n >= len) {
276 *nUsed = n;
277 return 0;
278 }
279 i = s[n++] & 0xff;
280 if (!vec[i].isVector) {
281 *nUsed = n;
282 return vec[i].cid;
283 }
284 vec = vec[i].vector;
285 }
286}
287
288//------------------------------------------------------------------------
289
290CMapCache::CMapCache() {
291 int i;
292
293 for (i = 0; i < cMapCacheSize; ++i) {
294 cache[i] = NULL;
295 }
296}
297
298CMapCache::~CMapCache() {
299 int i;
300
301 for (i = 0; i < cMapCacheSize; ++i) {
302 if (cache[i]) {
303 cache[i]->decRefCnt();
304 }
305 }
306}
307
308CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
309 CMap *cmap;
310 int i, j;
311
312 if (cache[0] && cache[0]->match(collection, cMapName)) {
313 cache[0]->incRefCnt();
314 return cache[0];
315 }
316 for (i = 1; i < cMapCacheSize; ++i) {
317 if (cache[i] && cache[i]->match(collection, cMapName)) {
318 cmap = cache[i];
319 for (j = i; j >= 1; --j) {
320 cache[j] = cache[j - 1];
321 }
322 cache[0] = cmap;
323 cmap->incRefCnt();
324 return cmap;
325 }
326 }
327 if ((cmap = CMap::parse(this, collection, cMapName))) {
328 if (cache[cMapCacheSize - 1]) {
329 cache[cMapCacheSize - 1]->decRefCnt();
330 }
331 for (j = cMapCacheSize - 1; j >= 1; --j) {
332 cache[j] = cache[j - 1];
333 }
334 cache[0] = cmap;
335 cmap->incRefCnt();
336 return cmap;
337 }
338 return NULL;
339}