/src/aspell/common/convert.cpp
Line | Count | Source |
1 | | // This file is part of The New Aspell |
2 | | // Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license |
3 | | // version 2.0 or 2.1. You should have received a copy of the LGPL |
4 | | // license along with this library if you did not you can find |
5 | | // it at http://www.gnu.org/. |
6 | | |
7 | | #include <assert.h> |
8 | | #include <string.h> |
9 | | #include <math.h> |
10 | | |
11 | | #include "asc_ctype.hpp" |
12 | | #include "convert.hpp" |
13 | | #include "fstream.hpp" |
14 | | #include "getdata.hpp" |
15 | | #include "config.hpp" |
16 | | #include "errors.hpp" |
17 | | #include "stack_ptr.hpp" |
18 | | #include "cache-t.hpp" |
19 | | #include "file_util.hpp" |
20 | | #include "file_data_util.hpp" |
21 | | #include "vararray.hpp" |
22 | | |
23 | | #include "iostream.hpp" |
24 | | |
25 | | #include "gettext.h" |
26 | | |
27 | | namespace acommon { |
28 | | |
29 | | typedef unsigned char byte; |
30 | | typedef unsigned char Uni8; |
31 | | typedef unsigned short Uni16; |
32 | | typedef unsigned int Uni32; |
33 | | |
34 | | |
35 | | ////////////////////////////////////////////////////////////////////// |
36 | | ////////////////////////////////////////////////////////////////////// |
37 | | // |
38 | | // Lookups |
39 | | // |
40 | | ////////////////////////////////////////////////////////////////////// |
41 | | ////////////////////////////////////////////////////////////////////// |
42 | | |
43 | | ////////////////////////////////////////////////////////////////////// |
44 | | // |
45 | | // ToUniLookup |
46 | | // |
47 | | |
48 | | class ToUniLookup |
49 | | { |
50 | | Uni32 data[256]; |
51 | | static const Uni32 npos = (Uni32)(-1); |
52 | | public: |
53 | | void reset(); |
54 | 442k | Uni32 operator[] (char key) const {return data[(unsigned char)key];} |
55 | 0 | bool have(char key) const {return data[(unsigned char)key] != npos;} |
56 | | bool insert(char key, Uni32 value); |
57 | | }; |
58 | | |
59 | | void ToUniLookup::reset() |
60 | 61 | { |
61 | 15.6k | for (int i = 0; i != 256; ++i) |
62 | 15.6k | data[i] = npos; |
63 | 61 | } |
64 | | |
65 | | bool ToUniLookup::insert(char key, Uni32 value) |
66 | 11.2k | { |
67 | 11.2k | if (data[(unsigned char)key] != npos) |
68 | 0 | return false; |
69 | 11.2k | data[(unsigned char)key] = value; |
70 | 11.2k | return true; |
71 | 11.2k | } |
72 | | |
73 | | ////////////////////////////////////////////////////////////////////// |
74 | | // |
75 | | // FromUniLookup |
76 | | // |
77 | | |
78 | | // Assumes that the maximum number of items in the table is 256 |
79 | | // Also assumes (unsigned char)i == i % 256 |
80 | | |
81 | | // Based on the iso-8859-* character sets it is very fast, almost all |
82 | | // lookups involving no more than 2 comparisons. |
83 | | // NO looks ups involded more than 3 compassions. |
84 | | // Also, no division (or modules) is done whatsoever. |
85 | | |
86 | | |
87 | | struct UniItem { |
88 | | Uni32 key; |
89 | | char value; |
90 | | }; |
91 | | |
92 | | class FromUniLookup |
93 | | { |
94 | | private: |
95 | | static const Uni32 npos = (Uni32)(-1); |
96 | | UniItem * overflow_end; |
97 | | |
98 | | UniItem data[256*4]; |
99 | | |
100 | | UniItem overflow[256]; // you can never be too careful; |
101 | | |
102 | | public: |
103 | 1.02k | FromUniLookup() {} |
104 | | void reset(); |
105 | | inline char operator() (Uni32 key, char unknown = '?') const; |
106 | | bool insert(Uni32 key, char value); |
107 | | }; |
108 | | |
109 | | void FromUniLookup::reset() |
110 | 61 | { |
111 | 62.5k | for (unsigned i = 0; i != 256*4; ++i) |
112 | 62.4k | data[i].key = npos; |
113 | 61 | overflow_end = overflow; |
114 | 61 | } |
115 | | |
116 | | inline char FromUniLookup::operator() (Uni32 k, char unknown) const |
117 | 26.2k | { |
118 | 26.2k | const UniItem * i = data + (unsigned char)k * 4; |
119 | | |
120 | 26.2k | if (i->key == k) return i->value; |
121 | 0 | ++i; |
122 | 0 | if (i->key == k) return i->value; |
123 | 0 | ++i; |
124 | 0 | if (i->key == k) return i->value; |
125 | 0 | ++i; |
126 | 0 | if (i->key == k) return i->value; |
127 | | |
128 | 0 | if (i->key == npos) return unknown; |
129 | | |
130 | 0 | for(i = overflow; i != overflow_end; ++i) |
131 | 0 | if (i->key == k) return i->value; |
132 | | |
133 | 0 | return unknown; |
134 | 0 | } |
135 | | |
136 | | bool FromUniLookup::insert(Uni32 k, char v) |
137 | 11.2k | { |
138 | 11.2k | UniItem * i = data + (unsigned char)k * 4; |
139 | 11.2k | UniItem * e = i + 4; |
140 | 12.6k | while (i != e && i->key != npos) { |
141 | 1.40k | if (i->key == k) |
142 | 0 | return false; |
143 | 1.40k | ++i; |
144 | 1.40k | } |
145 | 11.2k | if (i == e) { |
146 | 0 | for(i = overflow; i != overflow_end; ++i) |
147 | 0 | if (i->key == k) return false; |
148 | 0 | } |
149 | 11.2k | i->key = k; |
150 | 11.2k | i->value = v; |
151 | 11.2k | return true; |
152 | 11.2k | } |
153 | | |
154 | | ////////////////////////////////////////////////////////////////////// |
155 | | // |
156 | | // CharLookup |
157 | | // |
158 | | |
159 | | class CharLookup |
160 | | { |
161 | | private: |
162 | | int data[256]; |
163 | | public: |
164 | | void reset(); |
165 | 0 | char operator[] (char key) const {return data[(unsigned char)key];} |
166 | | bool insert(char key, char value); |
167 | | }; |
168 | | |
169 | 0 | void CharLookup::reset() { |
170 | 0 | for (int i = 0; i != 256; ++i) |
171 | 0 | data[i] = -1; |
172 | 0 | } |
173 | | |
174 | | bool CharLookup::insert(char key, char value) |
175 | 0 | { |
176 | 0 | if (data[(unsigned char)key] != -1) |
177 | 0 | return false; |
178 | 0 | data[(unsigned char)key] = value; |
179 | 0 | return true; |
180 | 0 | } |
181 | | |
182 | | ////////////////////////////////////////////////////////////////////// |
183 | | // |
184 | | // NormLookup |
185 | | // |
186 | | |
187 | | template <class T> |
188 | | struct NormTable |
189 | | { |
190 | | static const unsigned struct_size; |
191 | | unsigned mask; |
192 | | unsigned height; |
193 | | unsigned width; |
194 | | unsigned size; |
195 | | T * end; |
196 | | T data[1]; // hack for data[] |
197 | | }; |
198 | | |
199 | | template <class T> |
200 | | const unsigned NormTable<T>::struct_size = sizeof(NormTable<T>) - 1; |
201 | | |
202 | | template <class T, class From> |
203 | | struct NormLookupRet |
204 | | { |
205 | | const typename T::To * to; |
206 | | const From * last; |
207 | | NormLookupRet(const typename T::To * t, From * l) |
208 | 32.1M | : to(t), last(l) {}acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar const>::NormLookupRet(unsigned char const*, acommon::FilterChar const*) Line | Count | Source | 208 | 11.6M | : to(t), last(l) {} |
acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar>::NormLookupRet(unsigned char const*, acommon::FilterChar*) Line | Count | Source | 208 | 18.3M | : to(t), last(l) {} |
acommon::NormLookupRet<acommon::ToUniNormEntry, char const>::NormLookupRet(unsigned short const*, char const*) Line | Count | Source | 208 | 2.20M | : to(t), last(l) {} |
|
209 | | }; |
210 | | |
211 | | template <class T, class From> |
212 | | static inline NormLookupRet<T,From> norm_lookup(const NormTable<T> * d, |
213 | | From * s, From * stop, |
214 | | const typename T::To * def, |
215 | | From * prev) |
216 | 32.1M | { |
217 | 41.6M | loop: |
218 | 41.6M | if (s != stop) { |
219 | 41.6M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); |
220 | 48.7M | for (;;) { |
221 | 48.7M | if (i->from == static_cast<typename T::From>(*s)) { |
222 | 32.1M | if (i->sub_table) { |
223 | | // really tail recursion |
224 | 9.44M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} |
225 | 9.44M | d = (const NormTable<T> *)(i->sub_table); |
226 | 9.44M | s++; |
227 | 9.44M | goto loop; |
228 | 22.6M | } else { |
229 | 22.6M | return NormLookupRet<T,From>(i->to, s); |
230 | 22.6M | } |
231 | 32.1M | } else { |
232 | 16.6M | i += d->height; |
233 | 16.6M | if (i >= d->end) break; |
234 | 16.6M | } |
235 | 48.7M | } |
236 | 41.6M | } |
237 | 9.52M | return NormLookupRet<T,From>(def, prev); |
238 | 41.6M | } convert.cpp:acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar const> acommon::norm_lookup<acommon::FromUniNormEntry, acommon::FilterChar const>(acommon::NormTable<acommon::FromUniNormEntry> const*, acommon::FilterChar const*, acommon::FilterChar const*, acommon::FromUniNormEntry::To const*, acommon::FilterChar const*) Line | Count | Source | 216 | 11.6M | { | 217 | 16.2M | loop: | 218 | 16.2M | if (s != stop) { | 219 | 16.2M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 19.7M | for (;;) { | 221 | 19.7M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 11.6M | if (i->sub_table) { | 223 | | // really tail recursion | 224 | 4.61M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} | 225 | 4.61M | d = (const NormTable<T> *)(i->sub_table); | 226 | 4.61M | s++; | 227 | 4.61M | goto loop; | 228 | 7.04M | } else { | 229 | 7.04M | return NormLookupRet<T,From>(i->to, s); | 230 | 7.04M | } | 231 | 11.6M | } else { | 232 | 8.07M | i += d->height; | 233 | 8.07M | if (i >= d->end) break; | 234 | 8.07M | } | 235 | 19.7M | } | 236 | 16.2M | } | 237 | 4.61M | return NormLookupRet<T,From>(def, prev); | 238 | 16.2M | } |
convert.cpp:acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar> acommon::norm_lookup<acommon::FromUniNormEntry, acommon::FilterChar>(acommon::NormTable<acommon::FromUniNormEntry> const*, acommon::FilterChar*, acommon::FilterChar*, acommon::FromUniNormEntry::To const*, acommon::FilterChar*) Line | Count | Source | 216 | 18.3M | { | 217 | 23.1M | loop: | 218 | 23.1M | if (s != stop) { | 219 | 23.1M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 26.8M | for (;;) { | 221 | 26.8M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 18.2M | if (i->sub_table) { | 223 | | // really tail recursion | 224 | 4.83M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} | 225 | 4.83M | d = (const NormTable<T> *)(i->sub_table); | 226 | 4.83M | s++; | 227 | 4.83M | goto loop; | 228 | 13.4M | } else { | 229 | 13.4M | return NormLookupRet<T,From>(i->to, s); | 230 | 13.4M | } | 231 | 18.2M | } else { | 232 | 8.61M | i += d->height; | 233 | 8.61M | if (i >= d->end) break; | 234 | 8.61M | } | 235 | 26.8M | } | 236 | 23.1M | } | 237 | 4.91M | return NormLookupRet<T,From>(def, prev); | 238 | 23.1M | } |
convert.cpp:acommon::NormLookupRet<acommon::ToUniNormEntry, char const> acommon::norm_lookup<acommon::ToUniNormEntry, char const>(acommon::NormTable<acommon::ToUniNormEntry> const*, char const*, char const*, acommon::ToUniNormEntry::To const*, char const*) Line | Count | Source | 216 | 2.20M | { | 217 | 2.20M | loop: | 218 | 2.20M | if (s != stop) { | 219 | 2.20M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 2.20M | for (;;) { | 221 | 2.20M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 2.20M | if (i->sub_table) { | 223 | | // really tail recursion | 224 | 0 | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} | 225 | 0 | d = (const NormTable<T> *)(i->sub_table); | 226 | 0 | s++; | 227 | 0 | goto loop; | 228 | 2.20M | } else { | 229 | 2.20M | return NormLookupRet<T,From>(i->to, s); | 230 | 2.20M | } | 231 | 2.20M | } else { | 232 | 0 | i += d->height; | 233 | 0 | if (i >= d->end) break; | 234 | 0 | } | 235 | 2.20M | } | 236 | 2.20M | } | 237 | 0 | return NormLookupRet<T,From>(def, prev); | 238 | 2.20M | } |
|
239 | | |
240 | | template <class T> |
241 | | void free_norm_table(NormTable<T> * d) |
242 | 32.9k | { |
243 | 4.93M | for (T * cur = d->data; cur != d->end; ++cur) { |
244 | 4.89M | if (cur->sub_table) |
245 | 29.2k | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); |
246 | 4.89M | } |
247 | 32.9k | free(d); |
248 | 32.9k | } void acommon::free_norm_table<acommon::FromUniNormEntry>(acommon::NormTable<acommon::FromUniNormEntry>*) Line | Count | Source | 242 | 31.0k | { | 243 | 4.46M | for (T * cur = d->data; cur != d->end; ++cur) { | 244 | 4.42M | if (cur->sub_table) | 245 | 29.2k | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); | 246 | 4.42M | } | 247 | 31.0k | free(d); | 248 | 31.0k | } |
void acommon::free_norm_table<acommon::ToUniNormEntry>(acommon::NormTable<acommon::ToUniNormEntry>*) Line | Count | Source | 242 | 1.82k | { | 243 | 469k | for (T * cur = d->data; cur != d->end; ++cur) { | 244 | 467k | if (cur->sub_table) | 245 | 0 | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); | 246 | 467k | } | 247 | 1.82k | free(d); | 248 | 1.82k | } |
|
249 | | |
250 | | struct FromUniNormEntry |
251 | | { |
252 | | typedef Uni32 From; |
253 | | Uni32 from; |
254 | | typedef byte To; |
255 | | byte to[4]; |
256 | | static const From from_non_char = (From)(-1); |
257 | | static const To to_non_char = 0x10; |
258 | | static const unsigned max_to = 4; |
259 | | void * sub_table; |
260 | | } |
261 | | #ifdef __GNUC__ |
262 | | __attribute__ ((aligned (16))) |
263 | | #endif |
264 | | ; |
265 | | |
266 | | struct ToUniNormEntry |
267 | | { |
268 | | typedef byte From; |
269 | | byte from; |
270 | | typedef Uni16 To; |
271 | | Uni16 to[3]; |
272 | | static const From from_non_char = 0x10; |
273 | | static const To to_non_char = 0x10; |
274 | | static const unsigned max_to = 3; |
275 | | void * sub_table; |
276 | | } |
277 | | #ifdef __GNUC__ |
278 | | __attribute__ ((aligned (16))) |
279 | | #endif |
280 | | ; |
281 | | |
282 | | ////////////////////////////////////////////////////////////////////// |
283 | | // |
284 | | // read in char data |
285 | | // |
286 | | |
287 | | PosibErr<void> read_in_char_data (const Config & config, |
288 | | ParmStr encoding, |
289 | | ToUniLookup & to, |
290 | | FromUniLookup & from) |
291 | 61 | { |
292 | 61 | to.reset(); |
293 | 61 | from.reset(); |
294 | | |
295 | 61 | String dir1,dir2,file_name; |
296 | 61 | fill_data_dir(&config, dir1, dir2); |
297 | 61 | find_file(file_name,dir1,dir2,encoding,".cset"); |
298 | | |
299 | 61 | FStream data; |
300 | 61 | PosibErrBase err = data.open(file_name, "r"); |
301 | 61 | if (err.get_err()) { |
302 | 17 | char mesg[300]; |
303 | 17 | snprintf(mesg, 300, _("This could also mean that the file \"%s\" could not be opened for reading or does not exist."), |
304 | 17 | file_name.c_str()); |
305 | 17 | return make_err(unknown_encoding, encoding, mesg); |
306 | 17 | } |
307 | 44 | unsigned chr; |
308 | 44 | Uni32 uni; |
309 | 44 | String line; |
310 | 44 | char * p; |
311 | 132 | do { |
312 | 132 | p = get_nb_line(data, line); |
313 | 132 | } while (*p != '/'); |
314 | 11.3k | for (chr = 0; chr != 256; ++chr) { |
315 | 11.2k | p = get_nb_line(data, line); |
316 | 11.2k | if (strtoul(p, 0, 16) != chr) |
317 | 0 | return make_err(bad_file_format, file_name); |
318 | 11.2k | uni = strtoul(p + 3, 0, 16); |
319 | 11.2k | to.insert(chr, uni); |
320 | 11.2k | from.insert(uni, chr); |
321 | 11.2k | } |
322 | | |
323 | 44 | return no_err; |
324 | 44 | } |
325 | | |
326 | | ////////////////////////////////////////////////////////////////////// |
327 | | // |
328 | | // read in norm data |
329 | | // |
330 | | |
331 | | struct Tally |
332 | | { |
333 | | int size; |
334 | | Uni32 mask; |
335 | | int max; |
336 | | int * data; |
337 | 98.7k | Tally(int s, int * d) : size(s), mask(s - 1), max(0), data(d) { |
338 | 98.7k | memset(data, 0, sizeof(int)*size); |
339 | 98.7k | } |
340 | 5.03M | void add(Uni32 chr) { |
341 | 5.03M | Uni32 p = chr & mask; |
342 | 5.03M | data[p]++; |
343 | 5.03M | if (data[p] > max) max = data[p]; |
344 | 5.03M | } |
345 | | }; |
346 | | |
347 | | # define sanity(check) \ |
348 | 8.62M | if (!(check)) return sanity_fail(__FILE__, FUNC, __LINE__, #check) |
349 | | |
350 | | static PosibErrBase sanity_fail(const char * file, const char * func, |
351 | | unsigned line, const char * check_str) |
352 | 0 | { |
353 | 0 | char mesg[500]; |
354 | 0 | snprintf(mesg, 500, "%s:%d: %s: Assertion \"%s\" failed.", |
355 | 0 | file, line, func, check_str); |
356 | 0 | return make_err(bad_input_error, mesg); |
357 | 0 | } |
358 | | # define CREATE_NORM_TABLE(T, in, buf, res) \ |
359 | 32.9k | do { PosibErr<NormTable<T> *> pe( create_norm_table<T>(in,buf) );\ |
360 | 32.9k | if (pe.has_err()) return PosibErrBase(pe); \ |
361 | 32.9k | res = pe.data; } while(false) |
362 | | |
363 | | template <class T> |
364 | | static PosibErr< NormTable<T> * > create_norm_table(IStream & in, String & buf) |
365 | 32.9k | { |
366 | 32.9k | const char FUNC[] = "create_norm_table"; |
367 | 32.9k | const char * p = get_nb_line(in, buf); |
368 | 32.9k | sanity(*p == 'N'); |
369 | 32.9k | ++p; |
370 | 32.9k | int size = strtoul(p, (char **)&p, 10); |
371 | 32.9k | VARARRAY(T, d, size); |
372 | 32.9k | memset(d, 0, sizeof(T) * size); |
373 | 32.9k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); |
374 | 32.9k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); |
375 | 32.9k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); |
376 | 32.9k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); |
377 | 32.9k | T * cur = d; |
378 | 1.71M | while (p = get_nb_line(in, buf), *p != '.') { |
379 | 1.67M | Uni32 f = strtoul(p, (char **)&p, 16); |
380 | 1.67M | cur->from = static_cast<typename T::From>(f); |
381 | 1.67M | sanity(f == cur->from); |
382 | 1.67M | tally0.add(f); |
383 | 1.67M | tally1.add(f); |
384 | 1.67M | tally2.add(f); |
385 | 1.67M | ++p; |
386 | 1.67M | sanity(*p == '>'); |
387 | 1.67M | ++p; |
388 | 1.67M | sanity(*p == ' '); |
389 | 1.67M | ++p; |
390 | 1.67M | unsigned i = 0; |
391 | 1.67M | if (*p != '-') { |
392 | 3.43M | for (;; ++i) { |
393 | 3.43M | const char * q = p; |
394 | 3.43M | Uni32 t = strtoul(p, (char **)&p, 16); |
395 | 3.43M | if (q == p) break; |
396 | 1.75M | sanity(i < d->max_to); |
397 | 1.75M | cur->to[i] = static_cast<typename T::To>(t); |
398 | 1.75M | sanity(t == static_cast<Uni32>(cur->to[i])); |
399 | 1.75M | } |
400 | 1.67M | } else { |
401 | 0 | cur->to[0] = 0; |
402 | 0 | cur->to[1] = T::to_non_char; |
403 | 0 | } |
404 | 1.67M | if (*p == ' ') ++p; |
405 | 1.67M | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); |
406 | 1.67M | ++cur; |
407 | 1.67M | } |
408 | 32.9k | sanity(cur - d == size); |
409 | 32.9k | Tally * which = &tally0; |
410 | 32.9k | if (which->max > tally1.max) which = &tally1; |
411 | 32.9k | if (which->max > tally2.max) which = &tally2; |
412 | 32.9k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + |
413 | 32.9k | sizeof(T) * which->size * which->max); |
414 | 32.9k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); |
415 | 32.9k | final->mask = which->size - 1; |
416 | 32.9k | final->height = which->size; |
417 | 32.9k | final->width = which->max; |
418 | 32.9k | final->end = final->data + which->size * which->max; |
419 | 32.9k | final->size = size; |
420 | 1.71M | for (cur = d; cur != d + size; ++cur) { |
421 | 1.67M | T * dest = final->data + (cur->from & final->mask); |
422 | 1.74M | while (dest->from != 0) dest += final->height; |
423 | 1.67M | *dest = *cur; |
424 | 1.67M | if (dest->from == 0) dest->from = T::from_non_char; |
425 | 1.67M | } |
426 | 77.6k | for (T * dest = final->data; dest < final->end; dest += final->height) { |
427 | 44.7k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { |
428 | 3.65k | dest->from = T::from_non_char; |
429 | 3.65k | dest->to[0] = T::to_non_char; |
430 | 3.65k | } |
431 | 44.7k | } |
432 | 32.9k | return final; |
433 | 32.9k | } convert.cpp:acommon::PosibErr<acommon::NormTable<acommon::FromUniNormEntry>*> acommon::create_norm_table<acommon::FromUniNormEntry>(acommon::IStream&, acommon::String&) Line | Count | Source | 365 | 31.0k | { | 366 | 31.0k | const char FUNC[] = "create_norm_table"; | 367 | 31.0k | const char * p = get_nb_line(in, buf); | 368 | 31.0k | sanity(*p == 'N'); | 369 | 31.0k | ++p; | 370 | 31.0k | int size = strtoul(p, (char **)&p, 10); | 371 | 31.0k | VARARRAY(T, d, size); | 372 | 31.0k | memset(d, 0, sizeof(T) * size); | 373 | 31.0k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); | 374 | 31.0k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); | 375 | 31.0k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); | 376 | 31.0k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); | 377 | 31.0k | T * cur = d; | 378 | 1.24M | while (p = get_nb_line(in, buf), *p != '.') { | 379 | 1.21M | Uni32 f = strtoul(p, (char **)&p, 16); | 380 | 1.21M | cur->from = static_cast<typename T::From>(f); | 381 | 1.21M | sanity(f == cur->from); | 382 | 1.21M | tally0.add(f); | 383 | 1.21M | tally1.add(f); | 384 | 1.21M | tally2.add(f); | 385 | 1.21M | ++p; | 386 | 1.21M | sanity(*p == '>'); | 387 | 1.21M | ++p; | 388 | 1.21M | sanity(*p == ' '); | 389 | 1.21M | ++p; | 390 | 1.21M | unsigned i = 0; | 391 | 1.21M | if (*p != '-') { | 392 | 2.45M | for (;; ++i) { | 393 | 2.45M | const char * q = p; | 394 | 2.45M | Uni32 t = strtoul(p, (char **)&p, 16); | 395 | 2.45M | if (q == p) break; | 396 | 1.24M | sanity(i < d->max_to); | 397 | 1.24M | cur->to[i] = static_cast<typename T::To>(t); | 398 | 1.24M | sanity(t == static_cast<Uni32>(cur->to[i])); | 399 | 1.24M | } | 400 | 1.21M | } else { | 401 | 0 | cur->to[0] = 0; | 402 | 0 | cur->to[1] = T::to_non_char; | 403 | 0 | } | 404 | 1.21M | if (*p == ' ') ++p; | 405 | 1.21M | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); | 406 | 1.21M | ++cur; | 407 | 1.21M | } | 408 | 31.0k | sanity(cur - d == size); | 409 | 31.0k | Tally * which = &tally0; | 410 | 31.0k | if (which->max > tally1.max) which = &tally1; | 411 | 31.0k | if (which->max > tally2.max) which = &tally2; | 412 | 31.0k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + | 413 | 31.0k | sizeof(T) * which->size * which->max); | 414 | 31.0k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); | 415 | 31.0k | final->mask = which->size - 1; | 416 | 31.0k | final->height = which->size; | 417 | 31.0k | final->width = which->max; | 418 | 31.0k | final->end = final->data + which->size * which->max; | 419 | 31.0k | final->size = size; | 420 | 1.24M | for (cur = d; cur != d + size; ++cur) { | 421 | 1.21M | T * dest = final->data + (cur->from & final->mask); | 422 | 1.27M | while (dest->from != 0) dest += final->height; | 423 | 1.21M | *dest = *cur; | 424 | 1.21M | if (dest->from == 0) dest->from = T::from_non_char; | 425 | 1.21M | } | 426 | 74.0k | for (T * dest = final->data; dest < final->end; dest += final->height) { | 427 | 42.9k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { | 428 | 1.82k | dest->from = T::from_non_char; | 429 | 1.82k | dest->to[0] = T::to_non_char; | 430 | 1.82k | } | 431 | 42.9k | } | 432 | 31.0k | return final; | 433 | 31.0k | } |
convert.cpp:acommon::PosibErr<acommon::NormTable<acommon::ToUniNormEntry>*> acommon::create_norm_table<acommon::ToUniNormEntry>(acommon::IStream&, acommon::String&) Line | Count | Source | 365 | 1.82k | { | 366 | 1.82k | const char FUNC[] = "create_norm_table"; | 367 | 1.82k | const char * p = get_nb_line(in, buf); | 368 | 1.82k | sanity(*p == 'N'); | 369 | 1.82k | ++p; | 370 | 1.82k | int size = strtoul(p, (char **)&p, 10); | 371 | 1.82k | VARARRAY(T, d, size); | 372 | 1.82k | memset(d, 0, sizeof(T) * size); | 373 | 1.82k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); | 374 | 1.82k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); | 375 | 1.82k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); | 376 | 1.82k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); | 377 | 1.82k | T * cur = d; | 378 | 469k | while (p = get_nb_line(in, buf), *p != '.') { | 379 | 467k | Uni32 f = strtoul(p, (char **)&p, 16); | 380 | 467k | cur->from = static_cast<typename T::From>(f); | 381 | 467k | sanity(f == cur->from); | 382 | 467k | tally0.add(f); | 383 | 467k | tally1.add(f); | 384 | 467k | tally2.add(f); | 385 | 467k | ++p; | 386 | 467k | sanity(*p == '>'); | 387 | 467k | ++p; | 388 | 467k | sanity(*p == ' '); | 389 | 467k | ++p; | 390 | 467k | unsigned i = 0; | 391 | 467k | if (*p != '-') { | 392 | 984k | for (;; ++i) { | 393 | 984k | const char * q = p; | 394 | 984k | Uni32 t = strtoul(p, (char **)&p, 16); | 395 | 984k | if (q == p) break; | 396 | 516k | sanity(i < d->max_to); | 397 | 516k | cur->to[i] = static_cast<typename T::To>(t); | 398 | 516k | sanity(t == static_cast<Uni32>(cur->to[i])); | 399 | 516k | } | 400 | 467k | } else { | 401 | 0 | cur->to[0] = 0; | 402 | 0 | cur->to[1] = T::to_non_char; | 403 | 0 | } | 404 | 467k | if (*p == ' ') ++p; | 405 | 467k | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); | 406 | 467k | ++cur; | 407 | 467k | } | 408 | 1.82k | sanity(cur - d == size); | 409 | 1.82k | Tally * which = &tally0; | 410 | 1.82k | if (which->max > tally1.max) which = &tally1; | 411 | 1.82k | if (which->max > tally2.max) which = &tally2; | 412 | 1.82k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + | 413 | 1.82k | sizeof(T) * which->size * which->max); | 414 | 1.82k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); | 415 | 1.82k | final->mask = which->size - 1; | 416 | 1.82k | final->height = which->size; | 417 | 1.82k | final->width = which->max; | 418 | 1.82k | final->end = final->data + which->size * which->max; | 419 | 1.82k | final->size = size; | 420 | 469k | for (cur = d; cur != d + size; ++cur) { | 421 | 467k | T * dest = final->data + (cur->from & final->mask); | 422 | 467k | while (dest->from != 0) dest += final->height; | 423 | 467k | *dest = *cur; | 424 | 467k | if (dest->from == 0) dest->from = T::from_non_char; | 425 | 467k | } | 426 | 3.65k | for (T * dest = final->data; dest < final->end; dest += final->height) { | 427 | 1.82k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { | 428 | 1.82k | dest->from = T::from_non_char; | 429 | 1.82k | dest->to[0] = T::to_non_char; | 430 | 1.82k | } | 431 | 1.82k | } | 432 | 1.82k | return final; | 433 | 1.82k | } |
|
434 | | |
435 | | static PosibErr<void> init_norm_tables(FStream & in, NormTables * d) |
436 | 914 | { |
437 | 914 | const char FUNC[] = "init_norm_tables"; |
438 | 914 | String l; |
439 | 914 | get_nb_line(in, l); |
440 | 914 | remove_comments(l); |
441 | 914 | sanity (l == "INTERNAL"); |
442 | 914 | get_nb_line(in, l); |
443 | 914 | remove_comments(l); |
444 | 914 | sanity (l == "/"); |
445 | 914 | CREATE_NORM_TABLE(FromUniNormEntry, in, l, d->internal); |
446 | 914 | get_nb_line(in, l); |
447 | 914 | remove_comments(l); |
448 | 914 | sanity (l == "STRICT"); |
449 | 914 | char * p = get_nb_line(in, l); |
450 | 914 | remove_comments(l); |
451 | 914 | if (l == "/") { |
452 | 914 | CREATE_NORM_TABLE(FromUniNormEntry, in, l, d->strict_d); |
453 | 914 | d->strict = d->strict_d; |
454 | 914 | } else { |
455 | 0 | sanity(*p == '='); |
456 | 0 | ++p; ++p; |
457 | 0 | sanity(strcmp(p, "INTERNAL") == 0); |
458 | 0 | d->strict = d->internal; |
459 | 0 | } |
460 | 3.65k | while (get_nb_line(in, l)) { |
461 | 2.74k | remove_comments(l); |
462 | 2.74k | d->to_uni.push_back(NormTables::ToUniTable()); |
463 | 2.74k | NormTables::ToUniTable & e = d->to_uni.back(); |
464 | 2.74k | e.name.resize(l.size()); |
465 | 11.8k | for (unsigned i = 0; i != l.size(); ++i) |
466 | 9.14k | e.name[i] = asc_tolower(l[i]); |
467 | 2.74k | char * p = get_nb_line(in, l); |
468 | 2.74k | remove_comments(l); |
469 | 2.74k | if (l == "/") { |
470 | 1.82k | CREATE_NORM_TABLE(ToUniNormEntry, in, l, e.data); |
471 | 1.82k | e.ptr = e.data; |
472 | 1.82k | } else { |
473 | 914 | sanity(*p == '='); |
474 | 914 | ++p; ++p; |
475 | 3.65k | for (char * q = p; *q; ++q) *q = asc_tolower(*q); |
476 | 914 | Vector<NormTables::ToUniTable>::iterator i = d->to_uni.begin(); |
477 | 1.82k | while (i->name != p && i != d->to_uni.end()) ++i; |
478 | 914 | sanity(i != d->to_uni.end()); |
479 | 914 | e.ptr = i->ptr; |
480 | 914 | get_nb_line(in, l); |
481 | 914 | } |
482 | 2.74k | } |
483 | 914 | return no_err; |
484 | 914 | } |
485 | | |
486 | | PosibErr<NormTables *> NormTables::get_new(const String & encoding, |
487 | | const Config * config) |
488 | 914 | { |
489 | 914 | String dir1,dir2,file_name; |
490 | 914 | fill_data_dir(config, dir1, dir2); |
491 | 914 | find_file(file_name,dir1,dir2,encoding,".cmap"); |
492 | | |
493 | 914 | FStream in; |
494 | 914 | PosibErrBase err = in.open(file_name, "r"); |
495 | 914 | if (err.get_err()) { |
496 | 0 | char mesg[300]; |
497 | 0 | snprintf(mesg, 300, _("This could also mean that the file \"%s\" could not be opened for reading or does not exist."), |
498 | 0 | file_name.c_str()); |
499 | 0 | return make_err(unknown_encoding, encoding, mesg); // FIXME |
500 | 0 | } |
501 | | |
502 | 914 | NormTables * d = new NormTables; |
503 | 914 | d->key = encoding; |
504 | 914 | err = init_norm_tables(in, d); |
505 | 914 | if (err.has_err()) { |
506 | 0 | return make_err(bad_file_format, file_name, err.get_err()->mesg); |
507 | 0 | } |
508 | | |
509 | 914 | return d; |
510 | | |
511 | 914 | } |
512 | | |
513 | | NormTables::~NormTables() |
514 | 914 | { |
515 | 914 | free_norm_table<FromUniNormEntry>(internal); |
516 | 914 | if (strict_d) |
517 | 914 | free_norm_table<FromUniNormEntry>(strict_d); |
518 | 3.65k | for (unsigned i = 0; i != to_uni.size(); ++i) { |
519 | 2.74k | if (to_uni[i].data) |
520 | 1.82k | free_norm_table<ToUniNormEntry>(to_uni[i].data); |
521 | 2.74k | } |
522 | 914 | } |
523 | | |
524 | | ////////////////////////////////////////////////////////////////////// |
525 | | ////////////////////////////////////////////////////////////////////// |
526 | | // |
527 | | // Convert |
528 | | // |
529 | | ////////////////////////////////////////////////////////////////////// |
530 | | ////////////////////////////////////////////////////////////////////// |
531 | | |
532 | | |
533 | | bool operator== (const Convert & rhs, const Convert & lhs) |
534 | 0 | { |
535 | 0 | return strcmp(rhs.in_code(), lhs.in_code()) == 0 |
536 | 0 | && strcmp(rhs.out_code(), lhs.out_code()) == 0; |
537 | 0 | } |
538 | | |
539 | | ////////////////////////////////////////////////////////////////////// |
540 | | // |
541 | | // Trivial Conversion |
542 | | // |
543 | | |
544 | | const char * unsupported_null_term_wide_string_msg = |
545 | | "Null-terminated wide-character strings unsupported when used this way."; |
546 | | |
547 | | template <typename Chr> |
548 | | struct DecodeDirect : public Decode |
549 | | { |
550 | 965 | DecodeDirect() {type_width = sizeof(Chr);}acommon::DecodeDirect<unsigned char>::DecodeDirect() Line | Count | Source | 550 | 829 | DecodeDirect() {type_width = sizeof(Chr);} |
acommon::DecodeDirect<unsigned short>::DecodeDirect() Line | Count | Source | 550 | 28 | DecodeDirect() {type_width = sizeof(Chr);} |
acommon::DecodeDirect<unsigned int>::DecodeDirect() Line | Count | Source | 550 | 108 | DecodeDirect() {type_width = sizeof(Chr);} |
|
551 | 210k | void decode(const char * in0, int size, FilterCharVector & out) const { |
552 | 210k | const Chr * in = reinterpret_cast<const Chr *>(in0); |
553 | 210k | if (size == -sizeof(Chr)) { |
554 | 890k | for (;*in; ++in) |
555 | 693k | out.append(*in, sizeof(Chr)); |
556 | 196k | } else if (size <= -1) { |
557 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); |
558 | 0 | abort(); |
559 | 14.0k | } else { |
560 | 14.0k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); |
561 | 32.7M | for (;in != stop; ++in) |
562 | 32.7M | out.append(*in, sizeof(Chr)); |
563 | 14.0k | } |
564 | 210k | } acommon::DecodeDirect<unsigned char>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 551 | 208k | void decode(const char * in0, int size, FilterCharVector & out) const { | 552 | 208k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 553 | 208k | if (size == -sizeof(Chr)) { | 554 | 890k | for (;*in; ++in) | 555 | 693k | out.append(*in, sizeof(Chr)); | 556 | 196k | } else if (size <= -1) { | 557 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 558 | 0 | abort(); | 559 | 11.7k | } else { | 560 | 11.7k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 561 | 32.0M | for (;in != stop; ++in) | 562 | 32.0M | out.append(*in, sizeof(Chr)); | 563 | 11.7k | } | 564 | 208k | } |
acommon::DecodeDirect<unsigned short>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 551 | 1.85k | void decode(const char * in0, int size, FilterCharVector & out) const { | 552 | 1.85k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 553 | 1.85k | if (size == -sizeof(Chr)) { | 554 | 0 | for (;*in; ++in) | 555 | 0 | out.append(*in, sizeof(Chr)); | 556 | 1.85k | } else if (size <= -1) { | 557 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 558 | 0 | abort(); | 559 | 1.85k | } else { | 560 | 1.85k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 561 | 500k | for (;in != stop; ++in) | 562 | 498k | out.append(*in, sizeof(Chr)); | 563 | 1.85k | } | 564 | 1.85k | } |
acommon::DecodeDirect<unsigned int>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 551 | 483 | void decode(const char * in0, int size, FilterCharVector & out) const { | 552 | 483 | const Chr * in = reinterpret_cast<const Chr *>(in0); | 553 | 483 | if (size == -sizeof(Chr)) { | 554 | 0 | for (;*in; ++in) | 555 | 0 | out.append(*in, sizeof(Chr)); | 556 | 483 | } else if (size <= -1) { | 557 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 558 | 0 | abort(); | 559 | 483 | } else { | 560 | 483 | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 561 | 163k | for (;in != stop; ++in) | 562 | 163k | out.append(*in, sizeof(Chr)); | 563 | 483 | } | 564 | 483 | } |
|
565 | | PosibErr<void> decode_ec(const char * in0, int size, |
566 | 0 | FilterCharVector & out, ParmStr) const { |
567 | 0 | DecodeDirect::decode(in0, size, out); |
568 | 0 | return no_err; |
569 | 0 | } Unexecuted instantiation: acommon::DecodeDirect<unsigned char>::decode_ec(char const*, int, acommon::FilterCharVector&, acommon::ParmString const&) const Unexecuted instantiation: acommon::DecodeDirect<unsigned short>::decode_ec(char const*, int, acommon::FilterCharVector&, acommon::ParmString const&) const Unexecuted instantiation: acommon::DecodeDirect<unsigned int>::decode_ec(char const*, int, acommon::FilterCharVector&, acommon::ParmString const&) const |
570 | | }; |
571 | | |
572 | | template <typename Chr> |
573 | | struct EncodeDirect : public Encode |
574 | | { |
575 | 999 | EncodeDirect() {type_width = sizeof(Chr);}acommon::EncodeDirect<unsigned char>::EncodeDirect() Line | Count | Source | 575 | 829 | EncodeDirect() {type_width = sizeof(Chr);} |
acommon::EncodeDirect<unsigned short>::EncodeDirect() Line | Count | Source | 575 | 28 | EncodeDirect() {type_width = sizeof(Chr);} |
acommon::EncodeDirect<unsigned int>::EncodeDirect() Line | Count | Source | 575 | 142 | EncodeDirect() {type_width = sizeof(Chr);} |
|
576 | | void encode(const FilterChar * in, const FilterChar * stop, |
577 | 884k | CharVector & out) const { |
578 | 3.88M | for (; in != stop; ++in) { |
579 | 3.00M | Chr c = in->chr; |
580 | 3.00M | if (c != in->chr) c = '?'; |
581 | 3.00M | out.append(&c, sizeof(Chr)); |
582 | 3.00M | } |
583 | 884k | } acommon::EncodeDirect<unsigned char>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 577 | 688k | CharVector & out) const { | 578 | 2.99M | for (; in != stop; ++in) { | 579 | 2.31M | Chr c = in->chr; | 580 | 2.31M | if (c != in->chr) c = '?'; | 581 | 2.31M | out.append(&c, sizeof(Chr)); | 582 | 2.31M | } | 583 | 688k | } |
acommon::EncodeDirect<unsigned short>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 577 | 173k | CharVector & out) const { | 578 | 829k | for (; in != stop; ++in) { | 579 | 656k | Chr c = in->chr; | 580 | 656k | if (c != in->chr) c = '?'; | 581 | 656k | out.append(&c, sizeof(Chr)); | 582 | 656k | } | 583 | 173k | } |
acommon::EncodeDirect<unsigned int>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 577 | 22.6k | CharVector & out) const { | 578 | 57.7k | for (; in != stop; ++in) { | 579 | 35.0k | Chr c = in->chr; | 580 | 35.0k | if (c != in->chr) c = '?'; | 581 | 35.0k | out.append(&c, sizeof(Chr)); | 582 | 35.0k | } | 583 | 22.6k | } |
|
584 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
585 | 3.00k | CharVector & out, ParmStr orig) const { |
586 | 8.90k | for (; in != stop; ++in) { |
587 | 5.90k | Chr c = in->chr; |
588 | 5.90k | if (c != in->chr) { |
589 | 0 | char m[70]; |
590 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
591 | 0 | return make_err(invalid_string, orig, m); |
592 | 0 | } |
593 | | |
594 | 5.90k | out.append(&c, sizeof(Chr)); |
595 | 5.90k | } |
596 | 3.00k | return no_err; |
597 | 3.00k | } acommon::EncodeDirect<unsigned char>::encode_ec(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&, acommon::ParmString const&) const Line | Count | Source | 585 | 1.13k | CharVector & out, ParmStr orig) const { | 586 | 3.39k | for (; in != stop; ++in) { | 587 | 2.26k | Chr c = in->chr; | 588 | 2.26k | if (c != in->chr) { | 589 | 0 | char m[70]; | 590 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); | 591 | 0 | return make_err(invalid_string, orig, m); | 592 | 0 | } | 593 | | | 594 | 2.26k | out.append(&c, sizeof(Chr)); | 595 | 2.26k | } | 596 | 1.13k | return no_err; | 597 | 1.13k | } |
Unexecuted instantiation: acommon::EncodeDirect<unsigned short>::encode_ec(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&, acommon::ParmString const&) const acommon::EncodeDirect<unsigned int>::encode_ec(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&, acommon::ParmString const&) const Line | Count | Source | 585 | 1.87k | CharVector & out, ParmStr orig) const { | 586 | 5.51k | for (; in != stop; ++in) { | 587 | 3.63k | Chr c = in->chr; | 588 | 3.63k | if (c != in->chr) { | 589 | 0 | char m[70]; | 590 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); | 591 | 0 | return make_err(invalid_string, orig, m); | 592 | 0 | } | 593 | | | 594 | 3.63k | out.append(&c, sizeof(Chr)); | 595 | 3.63k | } | 596 | 1.87k | return no_err; | 597 | 1.87k | } |
|
598 | 49 | bool encode(FilterChar * &, FilterChar * &, FilterCharVector &) const { |
599 | 49 | return true; |
600 | 49 | } acommon::EncodeDirect<unsigned char>::encode(acommon::FilterChar*&, acommon::FilterChar*&, acommon::FilterCharVector&) const Line | Count | Source | 598 | 49 | bool encode(FilterChar * &, FilterChar * &, FilterCharVector &) const { | 599 | 49 | return true; | 600 | 49 | } |
Unexecuted instantiation: acommon::EncodeDirect<unsigned short>::encode(acommon::FilterChar*&, acommon::FilterChar*&, acommon::FilterCharVector&) const Unexecuted instantiation: acommon::EncodeDirect<unsigned int>::encode(acommon::FilterChar*&, acommon::FilterChar*&, acommon::FilterCharVector&) const |
601 | | }; |
602 | | |
603 | | template <typename Chr> |
604 | | struct ConvDirect : public DirectConv |
605 | | { |
606 | 28 | ConvDirect() {type_width = sizeof(Chr);}Unexecuted instantiation: acommon::ConvDirect<unsigned short>::ConvDirect() Unexecuted instantiation: acommon::ConvDirect<unsigned int>::ConvDirect() acommon::ConvDirect<char>::ConvDirect() Line | Count | Source | 606 | 28 | ConvDirect() {type_width = sizeof(Chr);} |
|
607 | 7.92k | void convert(const char * in0, int size, CharVector & out) const { |
608 | 7.92k | if (size == -sizeof(Chr)) { |
609 | 7.73k | const Chr * in = reinterpret_cast<const Chr *>(in0); |
610 | 32.9k | for (;*in != 0; ++in) |
611 | 25.2k | out.append(in, sizeof(Chr)); |
612 | 7.73k | } else if (size <= -1) { |
613 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); |
614 | 0 | abort(); |
615 | 191 | } else { |
616 | 191 | out.append(in0, size); |
617 | 191 | } |
618 | 7.92k | } Unexecuted instantiation: acommon::ConvDirect<unsigned short>::convert(char const*, int, acommon::String&) const Unexecuted instantiation: acommon::ConvDirect<unsigned int>::convert(char const*, int, acommon::String&) const acommon::ConvDirect<char>::convert(char const*, int, acommon::String&) const Line | Count | Source | 607 | 7.92k | void convert(const char * in0, int size, CharVector & out) const { | 608 | 7.92k | if (size == -sizeof(Chr)) { | 609 | 7.73k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 610 | 32.9k | for (;*in != 0; ++in) | 611 | 25.2k | out.append(in, sizeof(Chr)); | 612 | 7.73k | } else if (size <= -1) { | 613 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 614 | 0 | abort(); | 615 | 191 | } else { | 616 | 191 | out.append(in0, size); | 617 | 191 | } | 618 | 7.92k | } |
|
619 | | PosibErr<void> convert_ec(const char * in0, int size, |
620 | 0 | CharVector & out, ParmStr) const { |
621 | 0 | ConvDirect::convert(in0, size, out); |
622 | 0 | return no_err; |
623 | 0 | } Unexecuted instantiation: acommon::ConvDirect<unsigned short>::convert_ec(char const*, int, acommon::String&, acommon::ParmString const&) const Unexecuted instantiation: acommon::ConvDirect<unsigned int>::convert_ec(char const*, int, acommon::String&, acommon::ParmString const&) const Unexecuted instantiation: acommon::ConvDirect<char>::convert_ec(char const*, int, acommon::String&, acommon::ParmString const&) const |
624 | | }; |
625 | | |
626 | | ////////////////////////////////////////////////////////////////////// |
627 | | // |
628 | | // Lookup Conversion |
629 | | // |
630 | | |
631 | | struct DecodeLookup : public Decode |
632 | | { |
633 | | ToUniLookup lookup; |
634 | 39 | PosibErr<void> init(ParmStr code, const Config & c) { |
635 | 39 | FromUniLookup unused; |
636 | 39 | return read_in_char_data(c, code, lookup, unused); |
637 | 39 | } |
638 | 333 | void decode(const char * in, int size, FilterCharVector & out) const { |
639 | 333 | if (size == -1) { |
640 | 0 | for (;*in; ++in) |
641 | 0 | out.append(lookup[*in]); |
642 | 333 | } else { |
643 | 333 | const char * stop = in + size; |
644 | 442k | for (;in != stop; ++in) |
645 | 442k | out.append(lookup[*in]); |
646 | 333 | } |
647 | 333 | } |
648 | | PosibErr<void> decode_ec(const char * in, int size, |
649 | 0 | FilterCharVector & out, ParmStr) const { |
650 | 0 | DecodeLookup::decode(in, size, out); |
651 | 0 | return no_err; |
652 | 0 | } |
653 | | }; |
654 | | |
655 | | struct DecodeNormLookup : public Decode |
656 | | { |
657 | | typedef ToUniNormEntry E; |
658 | | NormTable<E> * data; |
659 | 8.18k | DecodeNormLookup(NormTable<E> * d) : data(d) {} |
660 | | // must be null terminated |
661 | | // FIXME: Why must it be null terminated? |
662 | 692k | void decode(const char * in, int size, FilterCharVector & out) const { |
663 | 692k | const char * stop = in + size; // will work even if size -1 |
664 | 2.89M | while (in != stop) { |
665 | 2.89M | if (*in == 0) { |
666 | 692k | if (size == -1) break; |
667 | 0 | out.append(0); |
668 | 0 | ++in; |
669 | 2.20M | } else { |
670 | 2.20M | NormLookupRet<E,const char> ret = norm_lookup<E>(data, in, stop, 0, in); |
671 | 4.40M | for (unsigned i = 0; ret.to[i] && i < E::max_to; ++i) |
672 | 2.20M | out.append(ret.to[i]); |
673 | 2.20M | in = ret.last + 1; |
674 | 2.20M | } |
675 | 2.89M | } |
676 | 692k | } |
677 | | PosibErr<void> decode_ec(const char * in, int size, |
678 | 0 | FilterCharVector & out, ParmStr) const { |
679 | 0 | DecodeNormLookup::decode(in, size, out); |
680 | 0 | return no_err; |
681 | 0 | } |
682 | | }; |
683 | | |
684 | | struct EncodeLookup : public Encode |
685 | | { |
686 | | FromUniLookup lookup; |
687 | | PosibErr<void> init(ParmStr code, const Config & c) |
688 | 22 | {ToUniLookup unused; |
689 | 22 | return read_in_char_data(c, code, unused, lookup);} |
690 | | void encode(const FilterChar * in, const FilterChar * stop, |
691 | 6.98k | CharVector & out) const { |
692 | 33.2k | for (; in != stop; ++in) { |
693 | 26.2k | out.append(lookup(*in)); |
694 | 26.2k | } |
695 | 6.98k | } |
696 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
697 | 0 | CharVector & out, ParmStr orig) const { |
698 | 0 | for (; in != stop; ++in) { |
699 | 0 | char c = lookup(*in, '\0'); |
700 | 0 | if (c == '\0' && in->chr != 0) { |
701 | 0 | char m[70]; |
702 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
703 | 0 | return make_err(invalid_string, orig, m); |
704 | 0 | } |
705 | 0 | out.append(c); |
706 | 0 | } |
707 | 0 | return no_err; |
708 | 0 | } |
709 | | bool encode(FilterChar * & in0, FilterChar * & stop, |
710 | 0 | FilterCharVector & out) const { |
711 | 0 | FilterChar * in = in0; |
712 | 0 | for (; in != stop; ++in) |
713 | 0 | *in = lookup(*in); |
714 | 0 | return true; |
715 | 0 | } |
716 | | }; |
717 | | |
718 | | struct EncodeNormLookup : public Encode |
719 | | { |
720 | | typedef FromUniNormEntry E; |
721 | | NormTable<E> * data; |
722 | 2.71k | EncodeNormLookup(NormTable<E> * d) : data(d) {} |
723 | | // *stop must equal 0 |
724 | | void encode(const FilterChar * in, const FilterChar * stop, |
725 | 11.2k | CharVector & out) const { |
726 | 11.6M | while (in < stop) { |
727 | 11.6M | if (*in == 0) { |
728 | 0 | out.append('\0'); |
729 | 0 | ++in; |
730 | 11.6M | } else { |
731 | 11.6M | NormLookupRet<E,const FilterChar> ret = norm_lookup<E>(data, in, stop, (const byte *)"?", in); |
732 | 23.2M | for (unsigned i = 0; i < E::max_to && ret.to[i]; ++i) |
733 | 11.6M | out.append(ret.to[i]); |
734 | 11.6M | in = ret.last + 1; |
735 | 11.6M | } |
736 | 11.6M | } |
737 | 11.2k | } |
738 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
739 | 20.4k | CharVector & out, ParmStr orig) const { |
740 | 61.2k | while (in < stop) { |
741 | 40.8k | if (*in == 0) { |
742 | 0 | out.append('\0'); |
743 | 0 | ++in; |
744 | 40.8k | } else { |
745 | 40.8k | NormLookupRet<E,const FilterChar> ret = norm_lookup<E>(data, in, stop, 0, in); |
746 | 40.8k | if (ret.to == 0) { |
747 | 0 | char m[70]; |
748 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
749 | 0 | return make_err(invalid_string, orig, m); |
750 | 0 | } |
751 | 81.6k | for (unsigned i = 0; i < E::max_to && ret.to[i]; ++i) |
752 | 40.8k | out.append(ret.to[i]); |
753 | 40.8k | in = ret.last + 1; |
754 | 40.8k | } |
755 | 40.8k | } |
756 | 20.4k | return no_err; |
757 | 20.4k | } |
758 | | bool encode(FilterChar * & in, FilterChar * & stop, |
759 | 877 | FilterCharVector & buf) const { |
760 | 877 | buf.clear(); |
761 | 20.5M | while (in < stop) { |
762 | 20.5M | if (*in == 0) { |
763 | 2.21M | buf.append(FilterChar(0)); |
764 | 2.21M | ++in; |
765 | 18.3M | } else { |
766 | 18.3M | NormLookupRet<E,FilterChar> ret = norm_lookup<E>(data, in, stop, (const byte *)"?", in); |
767 | 18.3M | const FilterChar * end = ret.last + 1; |
768 | 18.3M | unsigned width = 0; |
769 | 36.6M | for (; in != end; ++in) width += in->width; |
770 | 18.3M | buf.append(FilterChar(ret.to[0], width)); |
771 | 18.3M | for (unsigned i = 1; i < E::max_to && ret.to[i]; ++i) { |
772 | 48.5k | buf.append(FilterChar(ret.to[i],0)); |
773 | 48.5k | } |
774 | 18.3M | } |
775 | 20.5M | } |
776 | 877 | buf.append(0); |
777 | 877 | in = buf.pbegin(); |
778 | 877 | stop = buf.pend(); |
779 | 877 | return true; |
780 | 877 | } |
781 | | }; |
782 | | |
783 | | ////////////////////////////////////////////////////////////////////// |
784 | | // |
785 | | // UTF8 |
786 | | // |
787 | | |
788 | | #define get_check_next \ |
789 | 656 | if (in == stop) goto error; \ |
790 | 656 | c = *in; \ |
791 | 656 | if ((c & 0xC0/*1100 0000*/) != 0x80/*10xx xxxx*/) goto error;\ |
792 | 656 | ++in; \ |
793 | 653 | u <<= 6; \ |
794 | 653 | u |= c & 0x3F/*0011 1111*/; \ |
795 | 653 | ++w; |
796 | | |
797 | | static inline FilterChar from_utf8 (const char * & in, const char * stop = 0, |
798 | | Uni32 err_char = '?') |
799 | 48.1k | { |
800 | 48.1k | Uni32 u = (Uni32)(-1); |
801 | 48.1k | FilterChar::Width w = 1; |
802 | | |
803 | | // the first char is guaranteed not to be off the end |
804 | 48.1k | char c = *in; |
805 | 48.1k | ++in; |
806 | | |
807 | 48.1k | if ((c & 0x80/*1000 0000*/) == 0x00/*0xxx xxx*/) { |
808 | 47.8k | u = c; |
809 | 47.8k | } else if ((c & 0xE0/*1110 0000*/) == 0xC0/*110x xxxx*/) { // 2-byte wide |
810 | 149 | u = c & 0x1F/*0001 1111*/; |
811 | 298 | get_check_next; |
812 | 298 | } else if ((c & 0xF0/*1111 0000*/) == 0xE0/*1110 xxxx*/) { // 3-byte wide |
813 | 83 | u = c & 0x0F/*0000 1111*/; |
814 | 166 | get_check_next; |
815 | 166 | get_check_next; |
816 | 166 | } else if ((c & 0xF8/*1111 1000*/) == 0xF0/*1111 0xxx*/) { // 4-byte wide |
817 | 115 | u = c & 0x07/*0000 0111*/; |
818 | 229 | get_check_next; |
819 | 229 | get_check_next; |
820 | 226 | get_check_next; |
821 | 224 | } else { |
822 | 2 | goto error; |
823 | 2 | } |
824 | | |
825 | 48.1k | return FilterChar(u, w); |
826 | 5 | error: |
827 | 5 | return FilterChar(err_char, w); |
828 | 48.1k | } |
829 | | |
830 | | static inline void to_utf8 (FilterChar in, CharVector & out) |
831 | 0 | { |
832 | 0 | FilterChar::Chr c = in; |
833 | | |
834 | 0 | if (c < 0x80) { |
835 | 0 | out.append(c); |
836 | 0 | } |
837 | 0 | else if (c < 0x800) { |
838 | 0 | out.append(0xC0 | (c>>6)); |
839 | 0 | out.append(0x80 | (c & 0x3F)); |
840 | 0 | } |
841 | 0 | else if (c < 0x10000) { |
842 | 0 | out.append(0xE0 | (c>>12)); |
843 | 0 | out.append(0x80 | (c>>6 & 0x3F)); |
844 | 0 | out.append(0x80 | (c & 0x3F)); |
845 | 0 | } |
846 | 0 | else if (c < 0x200000) { |
847 | 0 | out.append(0xF0 | (c>>18)); |
848 | 0 | out.append(0x80 | (c>>12 & 0x3F)); |
849 | 0 | out.append(0x80 | (c>>6 & 0x3F)); |
850 | 0 | out.append(0x80 | (c & 0x3F)); |
851 | 0 | } |
852 | 0 | } |
853 | | |
854 | | struct DecodeUtf8 : public Decode |
855 | | { |
856 | | ToUniLookup lookup; |
857 | 0 | void decode(const char * in, int size, FilterCharVector & out) const { |
858 | 0 | if (size == -1) { |
859 | 0 | while (*in) |
860 | 0 | out.append(from_utf8(in)); |
861 | 0 | } else { |
862 | 0 | const char * stop = in + size; |
863 | 0 | while (in != stop) |
864 | 0 | out.append(from_utf8(in, stop)); |
865 | 0 | } |
866 | 0 | } |
867 | | PosibErr<void> decode_ec(const char * in, int size, |
868 | 23.4k | FilterCharVector & out, ParmStr orig) const { |
869 | 23.4k | const char * begin = in; |
870 | 23.4k | if (size == -1) { |
871 | 6.97k | while (*in) { |
872 | 5.09k | FilterChar c = from_utf8(in, 0, (Uni32)-1); |
873 | 5.09k | if (c == (Uni32)-1) goto error; |
874 | 5.09k | out.append(c); |
875 | 5.09k | } |
876 | 21.5k | } else { |
877 | 21.5k | const char * stop = in + size; |
878 | 64.6k | while (in != stop) { |
879 | 43.0k | FilterChar c = from_utf8(in, stop, (Uni32)-1); |
880 | 43.0k | if (c == (Uni32)-1) goto error; |
881 | 43.0k | out.append(c); |
882 | 43.0k | } |
883 | 21.5k | } |
884 | 23.4k | return no_err; |
885 | 5 | error: |
886 | 5 | char m[70]; |
887 | 5 | snprintf(m, 70, _("Invalid UTF-8 sequence at position %ld."), (long)(in - begin)); |
888 | 5 | return make_err(invalid_string, orig, m); |
889 | 23.4k | } |
890 | | }; |
891 | | |
892 | | struct EncodeUtf8 : public Encode |
893 | | { |
894 | | FromUniLookup lookup; |
895 | | void encode(const FilterChar * in, const FilterChar * stop, |
896 | 0 | CharVector & out) const { |
897 | 0 | for (; in != stop; ++in) { |
898 | 0 | to_utf8(*in, out); |
899 | 0 | } |
900 | 0 | } |
901 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
902 | 0 | CharVector & out, ParmStr) const { |
903 | 0 | for (; in != stop; ++in) { |
904 | 0 | to_utf8(*in, out); |
905 | 0 | } |
906 | 0 | return no_err; |
907 | 0 | } |
908 | | }; |
909 | | |
910 | | ////////////////////////////////////////////////////////////////////// |
911 | | // |
912 | | // Cache |
913 | | // |
914 | | |
915 | | static GlobalCache<Decode> decode_cache("decode"); |
916 | | static GlobalCache<Encode> encode_cache("encode"); |
917 | | static GlobalCache<NormTables> norm_tables_cache("norm_tables"); |
918 | | |
919 | | ////////////////////////////////////////////////////////////////////// |
920 | | // |
921 | | // new_aspell_convert |
922 | | // |
923 | | |
924 | | void Convert::generic_convert(const char * in, int size, CharVector & out) |
925 | 1.79k | { |
926 | 1.79k | buf_.clear(); |
927 | 1.79k | decode_->decode(in, size, buf_); |
928 | 1.79k | FilterChar * start = buf_.pbegin(); |
929 | 1.79k | FilterChar * stop = buf_.pend(); |
930 | 1.79k | if (!filter.empty()) |
931 | 1.79k | filter.process(start, stop); |
932 | 1.79k | encode_->encode(start, stop, out); |
933 | 1.79k | } |
934 | | |
935 | | const char * fix_encoding_str(ParmStr enc, String & buf) |
936 | 41.4k | { |
937 | 41.4k | buf.clear(); |
938 | 41.4k | buf.reserve(enc.size() + 1); |
939 | 446k | for (size_t i = 0; i != enc.size(); ++i) |
940 | 404k | buf.push_back(asc_tolower(enc[i])); |
941 | | |
942 | 41.4k | if (strncmp(buf.c_str(), "iso8859", 7) == 0) |
943 | 2.89k | buf.insert(buf.begin() + 3, '-'); // For backwards compatibility |
944 | | |
945 | 41.4k | if (buf == "ascii" || buf == "ansi_x3.4-1968") |
946 | 0 | return "iso-8859-1"; |
947 | 41.4k | else if (buf == "machine unsigned 16" || buf == "utf-16") |
948 | 56 | return "ucs-2"; |
949 | 41.4k | else if (buf == "machine unsigned 32" || buf == "utf-32") |
950 | 216 | return "ucs-4"; |
951 | 41.2k | else |
952 | 41.2k | return buf.c_str(); |
953 | 41.4k | } |
954 | | |
955 | | bool ascii_encoding(const Config & c, ParmStr enc0) |
956 | 2.15k | { |
957 | 2.15k | if (enc0.empty()) return true; |
958 | 2.15k | if (enc0 == "ANSI_X3.4-1968" |
959 | 2.15k | || enc0 == "ASCII" || enc0 == "ascii") return true; |
960 | 0 | String buf; |
961 | 0 | const char * enc = fix_encoding_str(enc0, buf); |
962 | 0 | if (strcmp(enc, "utf-8") == 0 |
963 | 0 | || strcmp(enc, "ucs-2") == 0 |
964 | 0 | || strcmp(enc, "ucs-4") == 0) return false; |
965 | 0 | String dir1,dir2,file_name; |
966 | 0 | fill_data_dir(&c, dir1, dir2); |
967 | 0 | file_name << dir1 << enc << ".cset"; |
968 | 0 | if (file_exists(file_name)) return false; |
969 | 0 | if (dir1 == dir2) return true; |
970 | 0 | file_name.clear(); |
971 | 0 | file_name << dir2 << enc << ".cset"; |
972 | 0 | return !file_exists(file_name); |
973 | 0 | } |
974 | | |
975 | | PosibErr<Convert *> internal_new_convert(const Config & c, |
976 | | ConvKey in, |
977 | | ConvKey out, |
978 | | bool if_needed, |
979 | | Normalize norm) |
980 | 19.2k | { |
981 | 19.2k | String in_s; |
982 | 19.2k | in.val = fix_encoding_str(in.val, in_s); |
983 | | |
984 | 19.2k | String out_s; |
985 | 19.2k | out.val = fix_encoding_str(out.val, out_s); |
986 | | |
987 | 19.2k | if (if_needed && in.val == out.val) return 0; |
988 | | |
989 | 11.5k | StackPtr<Convert> conv(new Convert); |
990 | 11.5k | switch (norm) { |
991 | 34 | case NormNone: |
992 | 34 | RET_ON_ERR(conv->init(c, in, out)); break; |
993 | 2.88k | case NormFrom: |
994 | 2.88k | RET_ON_ERR(conv->init_norm_from(c, in, out)); break; |
995 | 8.65k | case NormTo: |
996 | 8.65k | RET_ON_ERR(conv->init_norm_to(c, in, out)); break; |
997 | 11.5k | } |
998 | 11.5k | return conv.release(); |
999 | 11.5k | } |
1000 | | |
1001 | | PosibErr<Decode *> Decode::get_new(const ConvKey & k, const Config * c) |
1002 | 1.97k | { |
1003 | 1.97k | StackPtr<Decode> ptr; |
1004 | 1.97k | if (k.val == "iso-8859-1") { |
1005 | 829 | ptr.reset(new DecodeDirect<Uni8>); |
1006 | 1.14k | } else if (k.val == "ucs-2") { |
1007 | 28 | if (k.allow_ucs) |
1008 | 28 | ptr.reset(new DecodeDirect<Uni16>); |
1009 | 0 | else |
1010 | 0 | return make_err(encoding_not_supported, k.val); |
1011 | 1.11k | } else if (k.val == "ucs-4") { |
1012 | 108 | if (k.allow_ucs) |
1013 | 108 | ptr.reset(new DecodeDirect<Uni32>); |
1014 | 0 | else |
1015 | 0 | return make_err(encoding_not_supported, k.val); |
1016 | 1.00k | } else if (k.val == "utf-8") { |
1017 | 967 | ptr.reset(new DecodeUtf8); |
1018 | 967 | } else { |
1019 | 39 | ptr.reset(new DecodeLookup); |
1020 | 39 | } |
1021 | 1.97k | RET_ON_ERR(ptr->init(k.val, *c)); |
1022 | 1.95k | ptr->key = k.val; |
1023 | 1.95k | return ptr.release(); |
1024 | 1.97k | } |
1025 | | |
1026 | | PosibErr<Encode *> Encode::get_new(const ConvKey & k, const Config * c) |
1027 | 1.98k | { |
1028 | 1.98k | StackPtr<Encode> ptr; |
1029 | 1.98k | if (k.val == "iso-8859-1") { |
1030 | 829 | ptr.reset(new EncodeDirect<Uni8>); |
1031 | 1.15k | } else if (k.val == "ucs-2" && k.allow_ucs) { |
1032 | 28 | if (k.allow_ucs) |
1033 | 28 | ptr.reset(new EncodeDirect<Uni16>); |
1034 | 0 | else |
1035 | 0 | return make_err(encoding_not_supported, k.val); |
1036 | 1.13k | } else if (k.val == "ucs-4" && k.allow_ucs) { |
1037 | 142 | if (k.allow_ucs) |
1038 | 142 | ptr.reset(new EncodeDirect<Uni32>); |
1039 | 0 | else |
1040 | 0 | return make_err(encoding_not_supported, k.val); |
1041 | 989 | } else if (k.val == "utf-8") { |
1042 | 967 | ptr.reset(new EncodeUtf8); |
1043 | 967 | } else { |
1044 | 22 | ptr.reset(new EncodeLookup); |
1045 | 22 | } |
1046 | 1.98k | RET_ON_ERR(ptr->init(k.val, *c)); |
1047 | 1.98k | ptr->key = k.val; |
1048 | 1.98k | return ptr.release(); |
1049 | 1.98k | } |
1050 | | |
1051 | 11.5k | Convert::~Convert() {} |
1052 | | |
1053 | | PosibErr<void> Convert::init(const Config & c, const ConvKey & in, const ConvKey & out) |
1054 | 666 | { |
1055 | 666 | RET_ON_ERR(setup(decode_c, &decode_cache, &c, in)); |
1056 | 663 | decode_ = decode_c.get(); |
1057 | 663 | RET_ON_ERR(setup(encode_c, &encode_cache, &c, out)); |
1058 | 663 | encode_ = encode_c.get(); |
1059 | | |
1060 | 663 | conv_ = 0; |
1061 | 663 | if (in.val == out.val) { |
1062 | 28 | if (in.val == "ucs-2") { |
1063 | 0 | if (in.allow_ucs) { |
1064 | 0 | conv_ = new ConvDirect<Uni16>; |
1065 | 0 | } else { |
1066 | 0 | return make_err(encoding_not_supported, in.val); |
1067 | 0 | } |
1068 | 28 | } else if (in.val == "ucs-4") { |
1069 | 0 | if (in.allow_ucs) { |
1070 | 0 | conv_ = new ConvDirect<Uni32>; |
1071 | 0 | } else { |
1072 | 0 | return make_err(encoding_not_supported, in.val); |
1073 | 0 | } |
1074 | 28 | } else { |
1075 | 28 | conv_ = new ConvDirect<char>; |
1076 | 28 | } |
1077 | 28 | } |
1078 | | |
1079 | 663 | if (conv_) |
1080 | 28 | RET_ON_ERR(conv_->init(decode_, encode_, c)); |
1081 | | |
1082 | 663 | return no_err; |
1083 | 663 | } |
1084 | | |
1085 | | |
1086 | | PosibErr<void> Convert::init_norm_from(const Config & c, const ConvKey & in, const ConvKey & out) |
1087 | 2.88k | { |
1088 | 2.88k | if (!c.retrieve_bool("normalize") && !c.retrieve_bool("norm-required")) |
1089 | 156 | return init(c,in,out); |
1090 | | |
1091 | 2.72k | RET_ON_ERR(setup(norm_tables_, &norm_tables_cache, &c, out.val)); |
1092 | | |
1093 | 2.72k | RET_ON_ERR(setup(decode_c, &decode_cache, &c, in)); |
1094 | 2.71k | decode_ = decode_c.get(); |
1095 | | |
1096 | 2.71k | if (c.retrieve_bool("norm-strict")) { |
1097 | 27 | encode_s = new EncodeNormLookup(norm_tables_->strict); |
1098 | 27 | encode_ = encode_s; |
1099 | 27 | encode_->key = out.val; |
1100 | 27 | encode_->key += ":strict"; |
1101 | 2.68k | } else { |
1102 | 2.68k | encode_s = new EncodeNormLookup(norm_tables_->internal); |
1103 | 2.68k | encode_ = encode_s; |
1104 | 2.68k | encode_->key = out.val; |
1105 | 2.68k | encode_->key += ":internal"; |
1106 | 2.68k | } |
1107 | 2.71k | conv_ = 0; |
1108 | | |
1109 | 2.71k | return no_err; |
1110 | 2.72k | } |
1111 | | |
1112 | | PosibErr<void> Convert::init_norm_to(const Config & c, const ConvKey & in, const ConvKey & out) |
1113 | 8.65k | { |
1114 | 8.65k | String norm_form = c.retrieve("norm-form"); |
1115 | 8.65k | if ((!c.retrieve_bool("normalize") || norm_form == "none") |
1116 | 476 | && !c.retrieve_bool("norm-required")) |
1117 | 476 | return init(c,in,out); |
1118 | 8.18k | if (norm_form == "none" && c.retrieve_bool("norm-required")) |
1119 | 0 | norm_form = "nfc"; |
1120 | | |
1121 | 8.18k | RET_ON_ERR(setup(norm_tables_, &norm_tables_cache, &c, in.val)); |
1122 | | |
1123 | 8.18k | RET_ON_ERR(setup(encode_c, &encode_cache, &c, out)); |
1124 | 8.18k | encode_ = encode_c.get(); |
1125 | | |
1126 | 8.18k | NormTables::ToUni::const_iterator i = norm_tables_->to_uni.begin(); |
1127 | 16.3k | for (; i != norm_tables_->to_uni.end() && i->name != norm_form; ++i); |
1128 | 8.18k | if (i == norm_tables_->to_uni.end()) |
1129 | 0 | return make_err(aerror_bad_value, "norm-form", norm_form, "one of none, nfd, nfc, or comp"); |
1130 | | |
1131 | 8.18k | decode_s = new DecodeNormLookup(i->ptr); |
1132 | 8.18k | decode_ = decode_s; |
1133 | 8.18k | decode_->key = in.val; |
1134 | 8.18k | decode_->key += ':'; |
1135 | 8.18k | decode_->key += i->name; |
1136 | | |
1137 | 8.18k | conv_ = 0; |
1138 | | |
1139 | 8.18k | return no_err; |
1140 | 8.18k | } |
1141 | | |
1142 | | PosibErr<void> MBLen::setup(const Config &, ParmStr enc0) |
1143 | 0 | { |
1144 | 0 | String buf; |
1145 | 0 | const char * enc = fix_encoding_str(enc0,buf); |
1146 | 0 | if (strcmp(enc, "utf-8") == 0) encoding = UTF8; |
1147 | 0 | else if (strcmp(enc, "ucs-2") == 0) encoding = UCS2; |
1148 | 0 | else if (strcmp(enc, "ucs-4") == 0) encoding = UCS4; |
1149 | 0 | else encoding = Other; |
1150 | 0 | return no_err; |
1151 | 0 | } |
1152 | | |
1153 | | unsigned MBLen::operator()(const char * str, const char * stop) |
1154 | 0 | { |
1155 | 0 | unsigned size = 0; |
1156 | 0 | switch (encoding) { |
1157 | 0 | case Other: |
1158 | 0 | return stop - str; |
1159 | 0 | case UTF8: |
1160 | 0 | for (; str != stop; ++str) { |
1161 | 0 | if ((*str & 0x80) == 0 || (*str & 0xC0) == 0xC0) ++size; |
1162 | 0 | } |
1163 | 0 | return size; |
1164 | 0 | case UCS2: |
1165 | 0 | return (stop - str)/2; |
1166 | 0 | case UCS4: |
1167 | 0 | return (stop - str)/4; |
1168 | 0 | } |
1169 | 0 | return 0; |
1170 | 0 | } |
1171 | | |
1172 | 0 | PosibErr<void> unsupported_null_term_wide_string_err_(const char * func) { |
1173 | 0 | static bool reported_to_stderr = false; |
1174 | 0 | PosibErr<void> err = make_err(other_error, unsupported_null_term_wide_string_msg); |
1175 | 0 | if (!reported_to_stderr) { |
1176 | 0 | CERR.printf("ERROR: %s: %s\n", func, unsupported_null_term_wide_string_msg); |
1177 | 0 | reported_to_stderr = true; |
1178 | 0 | } |
1179 | 0 | return err; |
1180 | 0 | } |
1181 | | |
1182 | 0 | void unsupported_null_term_wide_string_abort_(const char * func) { |
1183 | 0 | CERR.printf("%s: %s\n", func, unsupported_null_term_wide_string_msg); |
1184 | 0 | abort(); |
1185 | 0 | } |
1186 | | |
1187 | | } |