beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / UnicodeMap.cc
blob1319666779b0cf66cf876ceea4ad515006c4a59c
1 //========================================================================
2 //
3 // UnicodeMap.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
18 // To see a description of the changes please see the Changelog file that
19 // came with your tarball or type make ChangeLog if you are building from git
21 //========================================================================
23 #include <config.h>
25 #ifdef USE_GCC_PRAGMAS
26 #pragma implementation
27 #endif
29 #include <stdio.h>
30 #include <string.h>
31 #include "goo/gmem.h"
32 #include "goo/gfile.h"
33 #include "goo/GooString.h"
34 #include "goo/GooList.h"
35 #include "Error.h"
36 #include "GlobalParams.h"
37 #include "UnicodeMap.h"
39 //------------------------------------------------------------------------
41 #define maxExtCode 16
43 struct UnicodeMapExt {
44 Unicode u; // Unicode char
45 char code[maxExtCode];
46 Guint nBytes;
49 //------------------------------------------------------------------------
51 UnicodeMap *UnicodeMap::parse(GooString *encodingNameA) {
52 FILE *f;
53 UnicodeMap *map;
54 UnicodeMapRange *range;
55 UnicodeMapExt *eMap;
56 int size, eMapsSize;
57 char buf[256];
58 int line, nBytes, i, x;
59 char *tok1, *tok2, *tok3;
60 char *tokptr;
62 if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) {
63 error(errSyntaxError, -1,
64 "Couldn't find unicodeMap file for the '{0:t}' encoding",
65 encodingNameA);
66 return NULL;
69 map = new UnicodeMap(encodingNameA->copy());
71 size = 8;
72 map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange));
73 eMapsSize = 0;
75 line = 1;
76 while (getLine(buf, sizeof(buf), f)) {
77 if ((tok1 = strtok_r(buf, " \t\r\n", &tokptr)) &&
78 (tok2 = strtok_r(NULL, " \t\r\n", &tokptr))) {
79 if (!(tok3 = strtok_r(NULL, " \t\r\n", &tokptr))) {
80 tok3 = tok2;
81 tok2 = tok1;
83 nBytes = strlen(tok3) / 2;
84 if (nBytes <= 4) {
85 if (map->len == size) {
86 size *= 2;
87 map->ranges = (UnicodeMapRange *)
88 greallocn(map->ranges, size, sizeof(UnicodeMapRange));
90 range = &map->ranges[map->len];
91 sscanf(tok1, "%x", &range->start);
92 sscanf(tok2, "%x", &range->end);
93 sscanf(tok3, "%x", &range->code);
94 range->nBytes = nBytes;
95 ++map->len;
96 } else if (tok2 == tok1) {
97 if (map->eMapsLen == eMapsSize) {
98 eMapsSize += 16;
99 map->eMaps = (UnicodeMapExt *)
100 greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt));
102 eMap = &map->eMaps[map->eMapsLen];
103 sscanf(tok1, "%x", &eMap->u);
104 for (i = 0; i < nBytes; ++i) {
105 sscanf(tok3 + i*2, "%2x", &x);
106 eMap->code[i] = (char)x;
108 eMap->nBytes = nBytes;
109 ++map->eMapsLen;
110 } else {
111 error(errSyntaxError, -1,
112 "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
113 line, encodingNameA);
115 } else {
116 error(errSyntaxError, -1,
117 "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
118 line, encodingNameA);
120 ++line;
123 fclose(f);
125 return map;
128 UnicodeMap::UnicodeMap(GooString *encodingNameA) {
129 encodingName = encodingNameA;
130 unicodeOut = gFalse;
131 kind = unicodeMapUser;
132 ranges = NULL;
133 len = 0;
134 eMaps = NULL;
135 eMapsLen = 0;
136 refCnt = 1;
137 #if MULTITHREADED
138 gInitMutex(&mutex);
139 #endif
142 UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
143 UnicodeMapRange *rangesA, int lenA) {
144 encodingName = new GooString(encodingNameA);
145 unicodeOut = unicodeOutA;
146 kind = unicodeMapResident;
147 ranges = rangesA;
148 len = lenA;
149 eMaps = NULL;
150 eMapsLen = 0;
151 refCnt = 1;
152 #if MULTITHREADED
153 gInitMutex(&mutex);
154 #endif
157 UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA,
158 UnicodeMapFunc funcA) {
159 encodingName = new GooString(encodingNameA);
160 unicodeOut = unicodeOutA;
161 kind = unicodeMapFunc;
162 func = funcA;
163 eMaps = NULL;
164 eMapsLen = 0;
165 refCnt = 1;
166 #if MULTITHREADED
167 gInitMutex(&mutex);
168 #endif
171 UnicodeMap::~UnicodeMap() {
172 delete encodingName;
173 if (kind == unicodeMapUser && ranges) {
174 gfree(ranges);
176 if (eMaps) {
177 gfree(eMaps);
179 #if MULTITHREADED
180 gDestroyMutex(&mutex);
181 #endif
184 void UnicodeMap::incRefCnt() {
185 #if MULTITHREADED
186 gLockMutex(&mutex);
187 #endif
188 ++refCnt;
189 #if MULTITHREADED
190 gUnlockMutex(&mutex);
191 #endif
194 void UnicodeMap::decRefCnt() {
195 GBool done;
197 #if MULTITHREADED
198 gLockMutex(&mutex);
199 #endif
200 done = --refCnt == 0;
201 #if MULTITHREADED
202 gUnlockMutex(&mutex);
203 #endif
204 if (done) {
205 delete this;
209 GBool UnicodeMap::match(GooString *encodingNameA) {
210 return !encodingName->cmp(encodingNameA);
213 int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) {
214 int a, b, m, n, i, j;
215 Guint code;
217 if (kind == unicodeMapFunc) {
218 return (*func)(u, buf, bufSize);
221 a = 0;
222 b = len;
223 if (u >= ranges[a].start) {
224 // invariant: ranges[a].start <= u < ranges[b].start
225 while (b - a > 1) {
226 m = (a + b) / 2;
227 if (u >= ranges[m].start) {
228 a = m;
229 } else if (u < ranges[m].start) {
230 b = m;
233 if (u <= ranges[a].end) {
234 n = ranges[a].nBytes;
235 if (n > bufSize) {
236 return 0;
238 code = ranges[a].code + (u - ranges[a].start);
239 for (i = n - 1; i >= 0; --i) {
240 buf[i] = (char)(code & 0xff);
241 code >>= 8;
243 return n;
247 for (i = 0; i < eMapsLen; ++i) {
248 if (eMaps[i].u == u) {
249 n = eMaps[i].nBytes;
250 for (j = 0; j < n; ++j) {
251 buf[j] = eMaps[i].code[j];
253 return n;
257 return 0;
260 //------------------------------------------------------------------------
262 UnicodeMapCache::UnicodeMapCache() {
263 int i;
265 for (i = 0; i < unicodeMapCacheSize; ++i) {
266 cache[i] = NULL;
270 UnicodeMapCache::~UnicodeMapCache() {
271 int i;
273 for (i = 0; i < unicodeMapCacheSize; ++i) {
274 if (cache[i]) {
275 cache[i]->decRefCnt();
280 UnicodeMap *UnicodeMapCache::getUnicodeMap(GooString *encodingName) {
281 UnicodeMap *map;
282 int i, j;
284 if (cache[0] && cache[0]->match(encodingName)) {
285 cache[0]->incRefCnt();
286 return cache[0];
288 for (i = 1; i < unicodeMapCacheSize; ++i) {
289 if (cache[i] && cache[i]->match(encodingName)) {
290 map = cache[i];
291 for (j = i; j >= 1; --j) {
292 cache[j] = cache[j - 1];
294 cache[0] = map;
295 map->incRefCnt();
296 return map;
299 if ((map = UnicodeMap::parse(encodingName))) {
300 if (cache[unicodeMapCacheSize - 1]) {
301 cache[unicodeMapCacheSize - 1]->decRefCnt();
303 for (j = unicodeMapCacheSize - 1; j >= 1; --j) {
304 cache[j] = cache[j - 1];
306 cache[0] = map;
307 map->incRefCnt();
308 return map;
310 return NULL;