UnicodeMap.cpp
1//========================================================================
2//
3// UnicodeMap.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 "GList.h"
21#include "Error.h"
22#include "GlobalParams.h"
23#include "UnicodeMap.h"
24
25//------------------------------------------------------------------------
26
27#define maxExtCode 16
28
29struct UnicodeMapExt {
30 Unicode u; // Unicode char
31 char code[maxExtCode];
32 Guint nBytes;
33};
34
35//------------------------------------------------------------------------
36
37UnicodeMap *UnicodeMap::parse(GString *encodingNameA) {
38 FILE *f;
39 UnicodeMap *map;
40 UnicodeMapRange *range;
41 UnicodeMapExt *eMap;
42 int size, eMapsSize;
43 char buf[256];
44 unsigned int x;
45 int line, nBytes, i;
46 char *tok1, *tok2, *tok3;
47
48 if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) {
49 error(-1, "Couldn't find unicodeMap file for the '%s' encoding",
50 encodingNameA->getCString());
51 return NULL;
52 }
53
54 map = new UnicodeMap(encodingNameA->copy());
55
56 size = 8;
57 map->ranges = (UnicodeMapRange *)gmalloc(size * sizeof(UnicodeMapRange));
58 eMapsSize = 0;
59
60 line = 1;
61 while (getLine(buf, sizeof(buf), f)) {
62 if ((tok1 = strtok(buf, " \t\r\n")) &&
63 (tok2 = strtok(NULL, " \t\r\n"))) {
64 if (!(tok3 = strtok(NULL, " \t\r\n"))) {
65 tok3 = tok2;
66 tok2 = tok1;
67 }
68 nBytes = strlen(tok3) / 2;
69 if (nBytes <= 4) {
70 if (map->len == size) {
71 size *= 2;
72 map->ranges = (UnicodeMapRange *)
73 grealloc(map->ranges, size * sizeof(UnicodeMapRange));
74 }
75 range = &map->ranges[map->len];
76 sscanf(tok1, "%x", &range->start);
77 sscanf(tok2, "%x", &range->end);
78 sscanf(tok3, "%x", &range->code);
79 range->nBytes = nBytes;
80 ++map->len;
81 } else if (tok2 == tok1) {
82 if (map->eMapsLen == eMapsSize) {
83 eMapsSize += 16;
84 map->eMaps = (UnicodeMapExt *)
85 grealloc(map->eMaps, eMapsSize * sizeof(UnicodeMapExt));
86 }
87 eMap = &map->eMaps[map->eMapsLen];
88 sscanf(tok1, "%x", &eMap->u);
89 for (i = 0; i < nBytes; ++i) {
90 sscanf(tok3 + i*2, "%2x", &x);
91 eMap->code[i] = (char)x;
92 }
93 eMap->nBytes = nBytes;
94 ++map->eMapsLen;
95 } else {
96 error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding",
97 line, encodingNameA->getCString());
98 }
99 } else {
100 error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding",
101 line, encodingNameA->getCString());
102 }
103 ++line;
104 }
105
106 fclose(f);
107
108 return map;
109}
110
111UnicodeMap::UnicodeMap(GString *encodingNameA) {
112 encodingName = encodingNameA;
113 unicodeOut = gFalse;
114 kind = unicodeMapUser;
115 ranges = NULL;
116 len = 0;
117 eMaps = NULL;
118 eMapsLen = 0;
119 refCnt = 1;
120}
121
122UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
123 UnicodeMapRange *rangesA, int lenA) {
124 encodingName = new GString(encodingNameA);
125 unicodeOut = unicodeOutA;
126 kind = unicodeMapResident;
127 ranges = rangesA;
128 len = lenA;
129 eMaps = NULL;
130 eMapsLen = 0;
131 refCnt = 1;
132}
133
134UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
135 UnicodeMapFunc funcA) {
136 encodingName = new GString(encodingNameA);
137 unicodeOut = unicodeOutA;
138 kind = unicodeMapFunc;
139 func = funcA;
140 eMaps = NULL;
141 eMapsLen = 0;
142 refCnt = 1;
143}
144
145UnicodeMap::~UnicodeMap() {
146 delete encodingName;
147 if (kind == unicodeMapUser && ranges) {
148 gfree(ranges);
149 }
150 if (eMaps) {
151 gfree(eMaps);
152 }
153}
154
155void UnicodeMap::incRefCnt() {
156 ++refCnt;
157}
158
159void UnicodeMap::decRefCnt() {
160 if (--refCnt == 0) {
161 delete this;
162 }
163}
164
165GBool UnicodeMap::match(GString *encodingNameA) {
166 return !encodingName->cmp(encodingNameA);
167}
168
169int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) {
170 int a, b, m, n, i, j;
171 Guint code;
172
173 if (kind == unicodeMapFunc) {
174 return (*func)(u, buf, bufSize);
175 }
176
177 a = 0;
178 b = len;
179 if (u < ranges[a].start) {
180 return 0;
181 }
182 // invariant: ranges[a].start <= u < ranges[b].start
183 while (b - a > 1) {
184 m = (a + b) / 2;
185 if (u >= ranges[m].start) {
186 a = m;
187 } else if (u < ranges[m].start) {
188 b = m;
189 }
190 }
191 if (u <= ranges[a].end) {
192 n = ranges[a].nBytes;
193 if (n > bufSize) {
194 return 0;
195 }
196 code = ranges[a].code + (u - ranges[a].start);
197 for (i = n - 1; i >= 0; --i) {
198 buf[i] = (char)(code & 0xff);
199 code >>= 8;
200 }
201 return n;
202 }
203
204 for (i = 0; i < eMapsLen; ++i) {
205 if (eMaps[i].u == u) {
206 n = eMaps[i].nBytes;
207 for (j = 0; j < n; ++j) {
208 buf[j] = eMaps[i].code[j];
209 }
210 return n;
211 }
212 }
213
214 return 0;
215}
216
217//------------------------------------------------------------------------
218
219UnicodeMapCache::UnicodeMapCache() {
220 int i;
221
222 for (i = 0; i < unicodeMapCacheSize; ++i) {
223 cache[i] = NULL;
224 }
225}
226
227UnicodeMapCache::~UnicodeMapCache() {
228 int i;
229
230 for (i = 0; i < unicodeMapCacheSize; ++i) {
231 if (cache[i]) {
232 cache[i]->decRefCnt();
233 }
234 }
235}
236
237UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) {
238 UnicodeMap *map;
239 int i, j;
240
241 if (cache[0] && cache[0]->match(encodingName)) {
242 cache[0]->incRefCnt();
243 return cache[0];
244 }
245 for (i = 1; i < unicodeMapCacheSize; ++i) {
246 if (cache[i] && cache[i]->match(encodingName)) {
247 map = cache[i];
248 for (j = i; j >= 1; --j) {
249 cache[j] = cache[j - 1];
250 }
251 cache[0] = map;
252 map->incRefCnt();
253 return map;
254 }
255 }
256 if ((map = UnicodeMap::parse(encodingName))) {
257 if (cache[unicodeMapCacheSize - 1]) {
258 cache[unicodeMapCacheSize - 1]->decRefCnt();
259 }
260 for (j = unicodeMapCacheSize - 1; j >= 1; --j) {
261 cache[j] = cache[j - 1];
262 }
263 cache[0] = map;
264 map->incRefCnt();
265 return map;
266 }
267 return NULL;
268}