1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
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 //========================================================================
25 #ifdef USE_GCC_PRAGMAS
26 #pragma implementation
32 #include "goo/gfile.h"
33 #include "goo/GooString.h"
34 #include "goo/GooList.h"
36 #include "GlobalParams.h"
37 #include "UnicodeMap.h"
39 //------------------------------------------------------------------------
43 struct UnicodeMapExt
{
44 Unicode u
; // Unicode char
45 char code
[maxExtCode
];
49 //------------------------------------------------------------------------
51 UnicodeMap
*UnicodeMap::parse(GooString
*encodingNameA
) {
54 UnicodeMapRange
*range
;
58 int line
, nBytes
, i
, x
;
59 char *tok1
, *tok2
, *tok3
;
62 if (!(f
= globalParams
->getUnicodeMapFile(encodingNameA
))) {
63 error(errSyntaxError
, -1,
64 "Couldn't find unicodeMap file for the '{0:t}' encoding",
69 map
= new UnicodeMap(encodingNameA
->copy());
72 map
->ranges
= (UnicodeMapRange
*)gmallocn(size
, sizeof(UnicodeMapRange
));
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
))) {
83 nBytes
= strlen(tok3
) / 2;
85 if (map
->len
== size
) {
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
;
96 } else if (tok2
== tok1
) {
97 if (map
->eMapsLen
== eMapsSize
) {
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
;
111 error(errSyntaxError
, -1,
112 "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
113 line
, encodingNameA
);
116 error(errSyntaxError
, -1,
117 "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding",
118 line
, encodingNameA
);
128 UnicodeMap::UnicodeMap(GooString
*encodingNameA
) {
129 encodingName
= encodingNameA
;
131 kind
= unicodeMapUser
;
142 UnicodeMap::UnicodeMap(const char *encodingNameA
, GBool unicodeOutA
,
143 UnicodeMapRange
*rangesA
, int lenA
) {
144 encodingName
= new GooString(encodingNameA
);
145 unicodeOut
= unicodeOutA
;
146 kind
= unicodeMapResident
;
157 UnicodeMap::UnicodeMap(const char *encodingNameA
, GBool unicodeOutA
,
158 UnicodeMapFunc funcA
) {
159 encodingName
= new GooString(encodingNameA
);
160 unicodeOut
= unicodeOutA
;
161 kind
= unicodeMapFunc
;
171 UnicodeMap::~UnicodeMap() {
173 if (kind
== unicodeMapUser
&& ranges
) {
180 gDestroyMutex(&mutex
);
184 void UnicodeMap::incRefCnt() {
190 gUnlockMutex(&mutex
);
194 void UnicodeMap::decRefCnt() {
200 done
= --refCnt
== 0;
202 gUnlockMutex(&mutex
);
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
;
217 if (kind
== unicodeMapFunc
) {
218 return (*func
)(u
, buf
, bufSize
);
223 if (u
>= ranges
[a
].start
) {
224 // invariant: ranges[a].start <= u < ranges[b].start
227 if (u
>= ranges
[m
].start
) {
229 } else if (u
< ranges
[m
].start
) {
233 if (u
<= ranges
[a
].end
) {
234 n
= ranges
[a
].nBytes
;
238 code
= ranges
[a
].code
+ (u
- ranges
[a
].start
);
239 for (i
= n
- 1; i
>= 0; --i
) {
240 buf
[i
] = (char)(code
& 0xff);
247 for (i
= 0; i
< eMapsLen
; ++i
) {
248 if (eMaps
[i
].u
== u
) {
250 for (j
= 0; j
< n
; ++j
) {
251 buf
[j
] = eMaps
[i
].code
[j
];
260 //------------------------------------------------------------------------
262 UnicodeMapCache::UnicodeMapCache() {
265 for (i
= 0; i
< unicodeMapCacheSize
; ++i
) {
270 UnicodeMapCache::~UnicodeMapCache() {
273 for (i
= 0; i
< unicodeMapCacheSize
; ++i
) {
275 cache
[i
]->decRefCnt();
280 UnicodeMap
*UnicodeMapCache::getUnicodeMap(GooString
*encodingName
) {
284 if (cache
[0] && cache
[0]->match(encodingName
)) {
285 cache
[0]->incRefCnt();
288 for (i
= 1; i
< unicodeMapCacheSize
; ++i
) {
289 if (cache
[i
] && cache
[i
]->match(encodingName
)) {
291 for (j
= i
; j
>= 1; --j
) {
292 cache
[j
] = cache
[j
- 1];
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];