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