/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 | 1.43M | 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 | 40 | { |
61 | 10.2k | for (int i = 0; i != 256; ++i) |
62 | 10.2k | data[i] = npos; |
63 | 40 | } |
64 | | |
65 | | bool ToUniLookup::insert(char key, Uni32 value) |
66 | 8.70k | { |
67 | 8.70k | if (data[(unsigned char)key] != npos) |
68 | 0 | return false; |
69 | 8.70k | data[(unsigned char)key] = value; |
70 | 8.70k | return true; |
71 | 8.70k | } |
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 | 794 | 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 | 40 | { |
111 | 41.0k | for (unsigned i = 0; i != 256*4; ++i) |
112 | 40.9k | data[i].key = npos; |
113 | 40 | overflow_end = overflow; |
114 | 40 | } |
115 | | |
116 | | inline char FromUniLookup::operator() (Uni32 k, char unknown) const |
117 | 20.2k | { |
118 | 20.2k | const UniItem * i = data + (unsigned char)k * 4; |
119 | | |
120 | 20.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 | 8.70k | { |
138 | 8.70k | UniItem * i = data + (unsigned char)k * 4; |
139 | 8.70k | UniItem * e = i + 4; |
140 | 10.0k | while (i != e && i->key != npos) { |
141 | 1.30k | if (i->key == k) |
142 | 0 | return false; |
143 | 1.30k | ++i; |
144 | 1.30k | } |
145 | 8.70k | if (i == e) { |
146 | 0 | for(i = overflow; i != overflow_end; ++i) |
147 | 0 | if (i->key == k) return false; |
148 | 0 | } |
149 | 8.70k | i->key = k; |
150 | 8.70k | i->value = v; |
151 | 8.70k | return true; |
152 | 8.70k | } |
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 | 38.9M | : to(t), last(l) {}acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar const>::NormLookupRet(unsigned char const*, acommon::FilterChar const*) Line | Count | Source | 208 | 14.8M | : to(t), last(l) {} |
acommon::NormLookupRet<acommon::FromUniNormEntry, acommon::FilterChar>::NormLookupRet(unsigned char const*, acommon::FilterChar*) Line | Count | Source | 208 | 21.8M | : to(t), last(l) {} |
acommon::NormLookupRet<acommon::ToUniNormEntry, char const>::NormLookupRet(unsigned short const*, char const*) Line | Count | Source | 208 | 2.24M | : 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 | 38.9M | { |
217 | 58.4M | loop: |
218 | 58.4M | if (s != stop) { |
219 | 58.4M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); |
220 | 64.0M | for (;;) { |
221 | 64.0M | if (i->from == static_cast<typename T::From>(*s)) { |
222 | 38.8M | if (i->sub_table) { |
223 | | // really tail recursion |
224 | 19.5M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} |
225 | 19.5M | d = (const NormTable<T> *)(i->sub_table); |
226 | 19.5M | s++; |
227 | 19.5M | goto loop; |
228 | 19.5M | } else { |
229 | 19.3M | return NormLookupRet<T,From>(i->to, s); |
230 | 19.3M | } |
231 | 38.8M | } else { |
232 | 25.2M | i += d->height; |
233 | 25.2M | if (i >= d->end) break; |
234 | 25.2M | } |
235 | 64.0M | } |
236 | 58.4M | } |
237 | 19.6M | return NormLookupRet<T,From>(def, prev); |
238 | 58.4M | } 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 | 14.8M | { | 217 | 24.2M | loop: | 218 | 24.2M | if (s != stop) { | 219 | 24.2M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 26.9M | for (;;) { | 221 | 26.9M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 14.8M | if (i->sub_table) { | 223 | | // really tail recursion | 224 | 9.38M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} | 225 | 9.38M | d = (const NormTable<T> *)(i->sub_table); | 226 | 9.38M | s++; | 227 | 9.38M | goto loop; | 228 | 9.38M | } else { | 229 | 5.43M | return NormLookupRet<T,From>(i->to, s); | 230 | 5.43M | } | 231 | 14.8M | } else { | 232 | 12.1M | i += d->height; | 233 | 12.1M | if (i >= d->end) break; | 234 | 12.1M | } | 235 | 26.9M | } | 236 | 24.2M | } | 237 | 9.38M | return NormLookupRet<T,From>(def, prev); | 238 | 24.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 | 21.8M | { | 217 | 32.0M | loop: | 218 | 32.0M | if (s != stop) { | 219 | 32.0M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 34.8M | for (;;) { | 221 | 34.8M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 21.7M | if (i->sub_table) { | 223 | | // really tail recursion | 224 | 10.1M | if (i->to[1] != T::to_non_char) {def = i->to; prev = s;} | 225 | 10.1M | d = (const NormTable<T> *)(i->sub_table); | 226 | 10.1M | s++; | 227 | 10.1M | goto loop; | 228 | 11.6M | } else { | 229 | 11.6M | return NormLookupRet<T,From>(i->to, s); | 230 | 11.6M | } | 231 | 21.7M | } else { | 232 | 13.0M | i += d->height; | 233 | 13.0M | if (i >= d->end) break; | 234 | 13.0M | } | 235 | 34.8M | } | 236 | 32.0M | } | 237 | 10.2M | return NormLookupRet<T,From>(def, prev); | 238 | 32.0M | } |
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.24M | { | 217 | 2.24M | loop: | 218 | 2.24M | if (s != stop) { | 219 | 2.24M | const T * i = d->data + (static_cast<typename T::From>(*s) & d->mask); | 220 | 2.24M | for (;;) { | 221 | 2.24M | if (i->from == static_cast<typename T::From>(*s)) { | 222 | 2.24M | 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.24M | } else { | 229 | 2.24M | return NormLookupRet<T,From>(i->to, s); | 230 | 2.24M | } | 231 | 2.24M | } else { | 232 | 0 | i += d->height; | 233 | 0 | if (i >= d->end) break; | 234 | 0 | } | 235 | 2.24M | } | 236 | 2.24M | } | 237 | 0 | return NormLookupRet<T,From>(def, prev); | 238 | 2.24M | } |
|
239 | | |
240 | | template <class T> |
241 | | void free_norm_table(NormTable<T> * d) |
242 | 25.4k | { |
243 | 3.81M | for (T * cur = d->data; cur != d->end; ++cur) { |
244 | 3.78M | if (cur->sub_table) |
245 | 22.6k | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); |
246 | 3.78M | } |
247 | 25.4k | free(d); |
248 | 25.4k | } void acommon::free_norm_table<acommon::FromUniNormEntry>(acommon::NormTable<acommon::FromUniNormEntry>*) Line | Count | Source | 242 | 24.0k | { | 243 | 3.45M | for (T * cur = d->data; cur != d->end; ++cur) { | 244 | 3.42M | if (cur->sub_table) | 245 | 22.6k | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); | 246 | 3.42M | } | 247 | 24.0k | free(d); | 248 | 24.0k | } |
void acommon::free_norm_table<acommon::ToUniNormEntry>(acommon::NormTable<acommon::ToUniNormEntry>*) Line | Count | Source | 242 | 1.41k | { | 243 | 363k | for (T * cur = d->data; cur != d->end; ++cur) { | 244 | 361k | if (cur->sub_table) | 245 | 0 | free_norm_table<T>(static_cast<NormTable<T> *>(cur->sub_table)); | 246 | 361k | } | 247 | 1.41k | free(d); | 248 | 1.41k | } |
|
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 | 40 | { |
292 | 40 | to.reset(); |
293 | 40 | from.reset(); |
294 | | |
295 | 40 | String dir1,dir2,file_name; |
296 | 40 | fill_data_dir(&config, dir1, dir2); |
297 | 40 | find_file(file_name,dir1,dir2,encoding,".cset"); |
298 | | |
299 | 40 | FStream data; |
300 | 40 | PosibErrBase err = data.open(file_name, "r"); |
301 | 40 | if (err.get_err()) { |
302 | 6 | char mesg[300]; |
303 | 6 | snprintf(mesg, 300, _("This could also mean that the file \"%s\" could not be opened for reading or does not exist."), |
304 | 6 | file_name.c_str()); |
305 | 6 | return make_err(unknown_encoding, encoding, mesg); |
306 | 6 | } |
307 | 34 | unsigned chr; |
308 | 34 | Uni32 uni; |
309 | 34 | String line; |
310 | 34 | char * p; |
311 | 102 | do { |
312 | 102 | p = get_nb_line(data, line); |
313 | 102 | } while (*p != '/'); |
314 | 8.73k | for (chr = 0; chr != 256; ++chr) { |
315 | 8.70k | p = get_nb_line(data, line); |
316 | 8.70k | if (strtoul(p, 0, 16) != chr) |
317 | 0 | return make_err(bad_file_format, file_name); |
318 | 8.70k | uni = strtoul(p + 3, 0, 16); |
319 | 8.70k | to.insert(chr, uni); |
320 | 8.70k | from.insert(uni, chr); |
321 | 8.70k | } |
322 | | |
323 | 34 | return no_err; |
324 | 34 | } |
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 | 76.3k | Tally(int s, int * d) : size(s), mask(s - 1), max(0), data(d) { |
338 | 76.3k | memset(data, 0, sizeof(int)*size); |
339 | 76.3k | } |
340 | 3.89M | void add(Uni32 chr) { |
341 | 3.89M | Uni32 p = chr & mask; |
342 | 3.89M | data[p]++; |
343 | 3.89M | if (data[p] > max) max = data[p]; |
344 | 3.89M | } |
345 | | }; |
346 | | |
347 | | # define sanity(check) \ |
348 | 7.96M | 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 | 25.4k | do { PosibErr<NormTable<T> *> pe( create_norm_table<T>(in,buf) );\ |
360 | 25.4k | if (pe.has_err()) return PosibErrBase(pe); \ |
361 | 25.4k | res = pe.data; } while(false) |
362 | | |
363 | | template <class T> |
364 | | static PosibErr< NormTable<T> * > create_norm_table(IStream & in, String & buf) |
365 | 25.4k | { |
366 | 25.4k | const char FUNC[] = "create_norm_table"; |
367 | 25.4k | const char * p = get_nb_line(in, buf); |
368 | 25.4k | sanity(*p == 'N'); |
369 | 25.4k | ++p; |
370 | 25.4k | int size = strtoul(p, (char **)&p, 10); |
371 | 25.4k | VARARRAY(T, d, size); |
372 | 25.4k | memset(d, 0, sizeof(T) * size); |
373 | 25.4k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); |
374 | 25.4k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); |
375 | 25.4k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); |
376 | 25.4k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); |
377 | 25.4k | T * cur = d; |
378 | 1.32M | while (p = get_nb_line(in, buf), *p != '.') { |
379 | 1.29M | sanity(cur - d < size); |
380 | 1.29M | Uni32 f = strtoul(p, (char **)&p, 16); |
381 | 1.29M | cur->from = static_cast<typename T::From>(f); |
382 | 1.29M | sanity(f == cur->from); |
383 | 1.29M | tally0.add(f); |
384 | 1.29M | tally1.add(f); |
385 | 1.29M | tally2.add(f); |
386 | 1.29M | ++p; |
387 | 1.29M | sanity(*p == '>'); |
388 | 1.29M | ++p; |
389 | 1.29M | sanity(*p == ' '); |
390 | 1.29M | ++p; |
391 | 1.29M | unsigned i = 0; |
392 | 1.29M | if (*p != '-') { |
393 | 2.65M | for (;; ++i) { |
394 | 2.65M | const char * q = p; |
395 | 2.65M | Uni32 t = strtoul(p, (char **)&p, 16); |
396 | 2.65M | if (q == p) break; |
397 | 1.36M | sanity(i < d->max_to); |
398 | 1.36M | cur->to[i] = static_cast<typename T::To>(t); |
399 | 1.36M | sanity(t == static_cast<Uni32>(cur->to[i])); |
400 | 1.36M | } |
401 | 1.29M | } else { |
402 | 0 | cur->to[0] = 0; |
403 | 0 | cur->to[1] = T::to_non_char; |
404 | 0 | } |
405 | 1.29M | if (*p == ' ') ++p; |
406 | 1.29M | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); |
407 | 1.29M | ++cur; |
408 | 1.29M | } |
409 | 25.4k | sanity(cur - d == size); |
410 | 25.4k | Tally * which = &tally0; |
411 | 25.4k | if (which->max > tally1.max) which = &tally1; |
412 | 25.4k | if (which->max > tally2.max) which = &tally2; |
413 | 25.4k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + |
414 | 25.4k | sizeof(T) * which->size * which->max); |
415 | 25.4k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); |
416 | 25.4k | final->mask = which->size - 1; |
417 | 25.4k | final->height = which->size; |
418 | 25.4k | final->width = which->max; |
419 | 25.4k | final->end = final->data + which->size * which->max; |
420 | 25.4k | final->size = size; |
421 | 1.32M | for (cur = d; cur != d + size; ++cur) { |
422 | 1.29M | T * dest = final->data + (cur->from & final->mask); |
423 | 1.35M | while (dest->from != 0) dest += final->height; |
424 | 1.29M | *dest = *cur; |
425 | 1.29M | if (dest->from == 0) dest->from = T::from_non_char; |
426 | 1.29M | } |
427 | 60.0k | for (T * dest = final->data; dest < final->end; dest += final->height) { |
428 | 34.6k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { |
429 | 2.82k | dest->from = T::from_non_char; |
430 | 2.82k | dest->to[0] = T::to_non_char; |
431 | 2.82k | } |
432 | 34.6k | } |
433 | 25.4k | return final; |
434 | 25.4k | } convert.cpp:acommon::PosibErr<acommon::NormTable<acommon::FromUniNormEntry>*> acommon::create_norm_table<acommon::FromUniNormEntry>(acommon::IStream&, acommon::String&) Line | Count | Source | 365 | 24.0k | { | 366 | 24.0k | const char FUNC[] = "create_norm_table"; | 367 | 24.0k | const char * p = get_nb_line(in, buf); | 368 | 24.0k | sanity(*p == 'N'); | 369 | 24.0k | ++p; | 370 | 24.0k | int size = strtoul(p, (char **)&p, 10); | 371 | 24.0k | VARARRAY(T, d, size); | 372 | 24.0k | memset(d, 0, sizeof(T) * size); | 373 | 24.0k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); | 374 | 24.0k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); | 375 | 24.0k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); | 376 | 24.0k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); | 377 | 24.0k | T * cur = d; | 378 | 960k | while (p = get_nb_line(in, buf), *p != '.') { | 379 | 936k | sanity(cur - d < size); | 380 | 936k | Uni32 f = strtoul(p, (char **)&p, 16); | 381 | 936k | cur->from = static_cast<typename T::From>(f); | 382 | 936k | sanity(f == cur->from); | 383 | 936k | tally0.add(f); | 384 | 936k | tally1.add(f); | 385 | 936k | tally2.add(f); | 386 | 936k | ++p; | 387 | 936k | sanity(*p == '>'); | 388 | 936k | ++p; | 389 | 936k | sanity(*p == ' '); | 390 | 936k | ++p; | 391 | 936k | unsigned i = 0; | 392 | 936k | if (*p != '-') { | 393 | 1.89M | for (;; ++i) { | 394 | 1.89M | const char * q = p; | 395 | 1.89M | Uni32 t = strtoul(p, (char **)&p, 16); | 396 | 1.89M | if (q == p) break; | 397 | 960k | sanity(i < d->max_to); | 398 | 960k | cur->to[i] = static_cast<typename T::To>(t); | 399 | 960k | sanity(t == static_cast<Uni32>(cur->to[i])); | 400 | 960k | } | 401 | 936k | } else { | 402 | 0 | cur->to[0] = 0; | 403 | 0 | cur->to[1] = T::to_non_char; | 404 | 0 | } | 405 | 936k | if (*p == ' ') ++p; | 406 | 936k | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); | 407 | 936k | ++cur; | 408 | 936k | } | 409 | 24.0k | sanity(cur - d == size); | 410 | 24.0k | Tally * which = &tally0; | 411 | 24.0k | if (which->max > tally1.max) which = &tally1; | 412 | 24.0k | if (which->max > tally2.max) which = &tally2; | 413 | 24.0k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + | 414 | 24.0k | sizeof(T) * which->size * which->max); | 415 | 24.0k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); | 416 | 24.0k | final->mask = which->size - 1; | 417 | 24.0k | final->height = which->size; | 418 | 24.0k | final->width = which->max; | 419 | 24.0k | final->end = final->data + which->size * which->max; | 420 | 24.0k | final->size = size; | 421 | 960k | for (cur = d; cur != d + size; ++cur) { | 422 | 936k | T * dest = final->data + (cur->from & final->mask); | 423 | 989k | while (dest->from != 0) dest += final->height; | 424 | 936k | *dest = *cur; | 425 | 936k | if (dest->from == 0) dest->from = T::from_non_char; | 426 | 936k | } | 427 | 57.2k | for (T * dest = final->data; dest < final->end; dest += final->height) { | 428 | 33.2k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { | 429 | 1.41k | dest->from = T::from_non_char; | 430 | 1.41k | dest->to[0] = T::to_non_char; | 431 | 1.41k | } | 432 | 33.2k | } | 433 | 24.0k | return final; | 434 | 24.0k | } |
convert.cpp:acommon::PosibErr<acommon::NormTable<acommon::ToUniNormEntry>*> acommon::create_norm_table<acommon::ToUniNormEntry>(acommon::IStream&, acommon::String&) Line | Count | Source | 365 | 1.41k | { | 366 | 1.41k | const char FUNC[] = "create_norm_table"; | 367 | 1.41k | const char * p = get_nb_line(in, buf); | 368 | 1.41k | sanity(*p == 'N'); | 369 | 1.41k | ++p; | 370 | 1.41k | int size = strtoul(p, (char **)&p, 10); | 371 | 1.41k | VARARRAY(T, d, size); | 372 | 1.41k | memset(d, 0, sizeof(T) * size); | 373 | 1.41k | int sz = 1 << (unsigned)floor(log(size <= 1 ? 1.0 : size - 1)/log(2.0)); | 374 | 1.41k | VARARRAY(int, tally0_d, sz); Tally tally0(sz, tally0_d); | 375 | 1.41k | VARARRAY(int, tally1_d, sz*2); Tally tally1(sz*2, tally1_d); | 376 | 1.41k | VARARRAY(int, tally2_d, sz*4); Tally tally2(sz*4, tally2_d); | 377 | 1.41k | T * cur = d; | 378 | 363k | while (p = get_nb_line(in, buf), *p != '.') { | 379 | 361k | sanity(cur - d < size); | 380 | 361k | Uni32 f = strtoul(p, (char **)&p, 16); | 381 | 361k | cur->from = static_cast<typename T::From>(f); | 382 | 361k | sanity(f == cur->from); | 383 | 361k | tally0.add(f); | 384 | 361k | tally1.add(f); | 385 | 361k | tally2.add(f); | 386 | 361k | ++p; | 387 | 361k | sanity(*p == '>'); | 388 | 361k | ++p; | 389 | 361k | sanity(*p == ' '); | 390 | 361k | ++p; | 391 | 361k | unsigned i = 0; | 392 | 361k | if (*p != '-') { | 393 | 761k | for (;; ++i) { | 394 | 761k | const char * q = p; | 395 | 761k | Uni32 t = strtoul(p, (char **)&p, 16); | 396 | 761k | if (q == p) break; | 397 | 399k | sanity(i < d->max_to); | 398 | 399k | cur->to[i] = static_cast<typename T::To>(t); | 399 | 399k | sanity(t == static_cast<Uni32>(cur->to[i])); | 400 | 399k | } | 401 | 361k | } else { | 402 | 0 | cur->to[0] = 0; | 403 | 0 | cur->to[1] = T::to_non_char; | 404 | 0 | } | 405 | 361k | if (*p == ' ') ++p; | 406 | 361k | if (*p == '/') CREATE_NORM_TABLE(T, in, buf, cur->sub_table); | 407 | 361k | ++cur; | 408 | 361k | } | 409 | 1.41k | sanity(cur - d == size); | 410 | 1.41k | Tally * which = &tally0; | 411 | 1.41k | if (which->max > tally1.max) which = &tally1; | 412 | 1.41k | if (which->max > tally2.max) which = &tally2; | 413 | 1.41k | NormTable<T> * final = (NormTable<T> *)calloc(1, NormTable<T>::struct_size + | 414 | 1.41k | sizeof(T) * which->size * which->max); | 415 | 1.41k | memset(final, 0, NormTable<T>::struct_size + sizeof(T) * which->size * which->max); | 416 | 1.41k | final->mask = which->size - 1; | 417 | 1.41k | final->height = which->size; | 418 | 1.41k | final->width = which->max; | 419 | 1.41k | final->end = final->data + which->size * which->max; | 420 | 1.41k | final->size = size; | 421 | 363k | for (cur = d; cur != d + size; ++cur) { | 422 | 361k | T * dest = final->data + (cur->from & final->mask); | 423 | 361k | while (dest->from != 0) dest += final->height; | 424 | 361k | *dest = *cur; | 425 | 361k | if (dest->from == 0) dest->from = T::from_non_char; | 426 | 361k | } | 427 | 2.82k | for (T * dest = final->data; dest < final->end; dest += final->height) { | 428 | 1.41k | if (dest->from == 0 || (dest->from == T::from_non_char && dest->to[0] == 0)) { | 429 | 1.41k | dest->from = T::from_non_char; | 430 | 1.41k | dest->to[0] = T::to_non_char; | 431 | 1.41k | } | 432 | 1.41k | } | 433 | 1.41k | return final; | 434 | 1.41k | } |
|
435 | | |
436 | | static PosibErr<void> init_norm_tables(FStream & in, NormTables * d) |
437 | 707 | { |
438 | 707 | const char FUNC[] = "init_norm_tables"; |
439 | 707 | String l; |
440 | 707 | get_nb_line(in, l); |
441 | 707 | remove_comments(l); |
442 | 707 | sanity (l == "INTERNAL"); |
443 | 707 | get_nb_line(in, l); |
444 | 707 | remove_comments(l); |
445 | 707 | sanity (l == "/"); |
446 | 707 | CREATE_NORM_TABLE(FromUniNormEntry, in, l, d->internal); |
447 | 707 | get_nb_line(in, l); |
448 | 707 | remove_comments(l); |
449 | 707 | sanity (l == "STRICT"); |
450 | 707 | char * p = get_nb_line(in, l); |
451 | 707 | remove_comments(l); |
452 | 707 | if (l == "/") { |
453 | 707 | CREATE_NORM_TABLE(FromUniNormEntry, in, l, d->strict_d); |
454 | 707 | d->strict = d->strict_d; |
455 | 707 | } else { |
456 | 0 | sanity(*p == '='); |
457 | 0 | ++p; ++p; |
458 | 0 | sanity(strcmp(p, "INTERNAL") == 0); |
459 | 0 | d->strict = d->internal; |
460 | 0 | } |
461 | 2.82k | while (get_nb_line(in, l)) { |
462 | 2.12k | remove_comments(l); |
463 | 2.12k | d->to_uni.push_back(NormTables::ToUniTable()); |
464 | 2.12k | NormTables::ToUniTable & e = d->to_uni.back(); |
465 | 2.12k | e.name.resize(l.size()); |
466 | 9.19k | for (unsigned i = 0; i != l.size(); ++i) |
467 | 7.07k | e.name[i] = asc_tolower(l[i]); |
468 | 2.12k | char * p = get_nb_line(in, l); |
469 | 2.12k | remove_comments(l); |
470 | 2.12k | if (l == "/") { |
471 | 1.41k | CREATE_NORM_TABLE(ToUniNormEntry, in, l, e.data); |
472 | 1.41k | e.ptr = e.data; |
473 | 1.41k | } else { |
474 | 707 | sanity(*p == '='); |
475 | 707 | ++p; ++p; |
476 | 2.82k | for (char * q = p; *q; ++q) *q = asc_tolower(*q); |
477 | 707 | Vector<NormTables::ToUniTable>::iterator i = d->to_uni.begin(); |
478 | 1.41k | while (i->name != p && i != d->to_uni.end()) ++i; |
479 | 707 | sanity(i != d->to_uni.end()); |
480 | 707 | e.ptr = i->ptr; |
481 | 707 | get_nb_line(in, l); |
482 | 707 | } |
483 | 2.12k | } |
484 | 707 | return no_err; |
485 | 707 | } |
486 | | |
487 | | PosibErr<NormTables *> NormTables::get_new(const String & encoding, |
488 | | const Config * config) |
489 | 707 | { |
490 | 707 | String dir1,dir2,file_name; |
491 | 707 | fill_data_dir(config, dir1, dir2); |
492 | 707 | find_file(file_name,dir1,dir2,encoding,".cmap"); |
493 | | |
494 | 707 | FStream in; |
495 | 707 | PosibErrBase err = in.open(file_name, "r"); |
496 | 707 | if (err.get_err()) { |
497 | 0 | char mesg[300]; |
498 | 0 | snprintf(mesg, 300, _("This could also mean that the file \"%s\" could not be opened for reading or does not exist."), |
499 | 0 | file_name.c_str()); |
500 | 0 | return make_err(unknown_encoding, encoding, mesg); // FIXME |
501 | 0 | } |
502 | | |
503 | 707 | NormTables * d = new NormTables; |
504 | 707 | d->key = encoding; |
505 | 707 | err = init_norm_tables(in, d); |
506 | 707 | if (err.has_err()) { |
507 | 0 | return make_err(bad_file_format, file_name, err.get_err()->mesg); |
508 | 0 | } |
509 | | |
510 | 707 | return d; |
511 | | |
512 | 707 | } |
513 | | |
514 | | NormTables::~NormTables() |
515 | 707 | { |
516 | 707 | free_norm_table<FromUniNormEntry>(internal); |
517 | 707 | if (strict_d) |
518 | 707 | free_norm_table<FromUniNormEntry>(strict_d); |
519 | 2.82k | for (unsigned i = 0; i != to_uni.size(); ++i) { |
520 | 2.12k | if (to_uni[i].data) |
521 | 1.41k | free_norm_table<ToUniNormEntry>(to_uni[i].data); |
522 | 2.12k | } |
523 | 707 | } |
524 | | |
525 | | ////////////////////////////////////////////////////////////////////// |
526 | | ////////////////////////////////////////////////////////////////////// |
527 | | // |
528 | | // Convert |
529 | | // |
530 | | ////////////////////////////////////////////////////////////////////// |
531 | | ////////////////////////////////////////////////////////////////////// |
532 | | |
533 | | |
534 | | bool operator== (const Convert & rhs, const Convert & lhs) |
535 | 0 | { |
536 | 0 | return strcmp(rhs.in_code(), lhs.in_code()) == 0 |
537 | 0 | && strcmp(rhs.out_code(), lhs.out_code()) == 0; |
538 | 0 | } |
539 | | |
540 | | ////////////////////////////////////////////////////////////////////// |
541 | | // |
542 | | // Trivial Conversion |
543 | | // |
544 | | |
545 | | const char * unsupported_null_term_wide_string_msg = |
546 | | "Null-terminated wide-character strings unsupported when used this way."; |
547 | | |
548 | | template <typename Chr> |
549 | | struct DecodeDirect : public Decode |
550 | | { |
551 | 759 | DecodeDirect() {type_width = sizeof(Chr);}acommon::DecodeDirect<unsigned char>::DecodeDirect() Line | Count | Source | 551 | 675 | DecodeDirect() {type_width = sizeof(Chr);} |
acommon::DecodeDirect<unsigned short>::DecodeDirect() Line | Count | Source | 551 | 16 | DecodeDirect() {type_width = sizeof(Chr);} |
acommon::DecodeDirect<unsigned int>::DecodeDirect() Line | Count | Source | 551 | 68 | DecodeDirect() {type_width = sizeof(Chr);} |
|
552 | 173k | void decode(const char * in0, int size, FilterCharVector & out) const { |
553 | 173k | const Chr * in = reinterpret_cast<const Chr *>(in0); |
554 | 173k | if (size == -sizeof(Chr)) { |
555 | 635k | for (;*in; ++in) |
556 | 473k | out.append(*in, sizeof(Chr)); |
557 | 162k | } else if (size <= -1) { |
558 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); |
559 | 0 | abort(); |
560 | 11.7k | } else { |
561 | 11.7k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); |
562 | 37.1M | for (;in != stop; ++in) |
563 | 37.1M | out.append(*in, sizeof(Chr)); |
564 | 11.7k | } |
565 | 173k | } acommon::DecodeDirect<unsigned char>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 552 | 171k | void decode(const char * in0, int size, FilterCharVector & out) const { | 553 | 171k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 554 | 171k | if (size == -sizeof(Chr)) { | 555 | 635k | for (;*in; ++in) | 556 | 473k | out.append(*in, sizeof(Chr)); | 557 | 162k | } else if (size <= -1) { | 558 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 559 | 0 | abort(); | 560 | 9.33k | } else { | 561 | 9.33k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 562 | 36.9M | for (;in != stop; ++in) | 563 | 36.9M | out.append(*in, sizeof(Chr)); | 564 | 9.33k | } | 565 | 171k | } |
acommon::DecodeDirect<unsigned short>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 552 | 1.02k | void decode(const char * in0, int size, FilterCharVector & out) const { | 553 | 1.02k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 554 | 1.02k | if (size == -sizeof(Chr)) { | 555 | 0 | for (;*in; ++in) | 556 | 0 | out.append(*in, sizeof(Chr)); | 557 | 1.02k | } else if (size <= -1) { | 558 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 559 | 0 | abort(); | 560 | 1.02k | } else { | 561 | 1.02k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 562 | 73.4k | for (;in != stop; ++in) | 563 | 72.3k | out.append(*in, sizeof(Chr)); | 564 | 1.02k | } | 565 | 1.02k | } |
acommon::DecodeDirect<unsigned int>::decode(char const*, int, acommon::FilterCharVector&) const Line | Count | Source | 552 | 1.40k | void decode(const char * in0, int size, FilterCharVector & out) const { | 553 | 1.40k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 554 | 1.40k | if (size == -sizeof(Chr)) { | 555 | 0 | for (;*in; ++in) | 556 | 0 | out.append(*in, sizeof(Chr)); | 557 | 1.40k | } else if (size <= -1) { | 558 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 559 | 0 | abort(); | 560 | 1.40k | } else { | 561 | 1.40k | const Chr * stop = reinterpret_cast<const Chr *>(in0) + size/sizeof(Chr); | 562 | 167k | for (;in != stop; ++in) | 563 | 166k | out.append(*in, sizeof(Chr)); | 564 | 1.40k | } | 565 | 1.40k | } |
|
566 | | PosibErr<void> decode_ec(const char * in0, int size, |
567 | 0 | FilterCharVector & out, ParmStr) const { |
568 | 0 | DecodeDirect::decode(in0, size, out); |
569 | 0 | return no_err; |
570 | 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 |
571 | | }; |
572 | | |
573 | | template <typename Chr> |
574 | | struct EncodeDirect : public Encode |
575 | | { |
576 | 786 | EncodeDirect() {type_width = sizeof(Chr);}acommon::EncodeDirect<unsigned char>::EncodeDirect() Line | Count | Source | 576 | 675 | EncodeDirect() {type_width = sizeof(Chr);} |
acommon::EncodeDirect<unsigned short>::EncodeDirect() Line | Count | Source | 576 | 16 | EncodeDirect() {type_width = sizeof(Chr);} |
acommon::EncodeDirect<unsigned int>::EncodeDirect() Line | Count | Source | 576 | 95 | EncodeDirect() {type_width = sizeof(Chr);} |
|
577 | | void encode(const FilterChar * in, const FilterChar * stop, |
578 | 650k | CharVector & out) const { |
579 | 3.49M | for (; in != stop; ++in) { |
580 | 2.84M | Chr c = in->chr; |
581 | 2.84M | if (c != in->chr) c = '?'; |
582 | 2.84M | out.append(&c, sizeof(Chr)); |
583 | 2.84M | } |
584 | 650k | } acommon::EncodeDirect<unsigned char>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 578 | 488k | CharVector & out) const { | 579 | 2.86M | for (; in != stop; ++in) { | 580 | 2.37M | Chr c = in->chr; | 581 | 2.37M | if (c != in->chr) c = '?'; | 582 | 2.37M | out.append(&c, sizeof(Chr)); | 583 | 2.37M | } | 584 | 488k | } |
acommon::EncodeDirect<unsigned short>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 578 | 80.8k | CharVector & out) const { | 579 | 361k | for (; in != stop; ++in) { | 580 | 280k | Chr c = in->chr; | 581 | 280k | if (c != in->chr) c = '?'; | 582 | 280k | out.append(&c, sizeof(Chr)); | 583 | 280k | } | 584 | 80.8k | } |
acommon::EncodeDirect<unsigned int>::encode(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&) const Line | Count | Source | 578 | 80.6k | CharVector & out) const { | 579 | 271k | for (; in != stop; ++in) { | 580 | 190k | Chr c = in->chr; | 581 | 190k | if (c != in->chr) c = '?'; | 582 | 190k | out.append(&c, sizeof(Chr)); | 583 | 190k | } | 584 | 80.6k | } |
|
585 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
586 | 2.81k | CharVector & out, ParmStr orig) const { |
587 | 16.1k | for (; in != stop; ++in) { |
588 | 13.3k | Chr c = in->chr; |
589 | 13.3k | if (c != in->chr) { |
590 | 0 | char m[70]; |
591 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
592 | 0 | return make_err(invalid_string, orig, m); |
593 | 0 | } |
594 | | |
595 | 13.3k | out.append(&c, sizeof(Chr)); |
596 | 13.3k | } |
597 | 2.81k | return no_err; |
598 | 2.81k | } acommon::EncodeDirect<unsigned char>::encode_ec(acommon::FilterChar const*, acommon::FilterChar const*, acommon::String&, acommon::ParmString const&) const Line | Count | Source | 586 | 1.08k | CharVector & out, ParmStr orig) const { | 587 | 3.25k | for (; in != stop; ++in) { | 588 | 2.17k | Chr c = in->chr; | 589 | 2.17k | if (c != in->chr) { | 590 | 0 | char m[70]; | 591 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); | 592 | 0 | return make_err(invalid_string, orig, m); | 593 | 0 | } | 594 | | | 595 | 2.17k | out.append(&c, sizeof(Chr)); | 596 | 2.17k | } | 597 | 1.08k | return no_err; | 598 | 1.08k | } |
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 | 586 | 1.73k | CharVector & out, ParmStr orig) const { | 587 | 12.9k | for (; in != stop; ++in) { | 588 | 11.1k | Chr c = in->chr; | 589 | 11.1k | if (c != in->chr) { | 590 | 0 | char m[70]; | 591 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); | 592 | 0 | return make_err(invalid_string, orig, m); | 593 | 0 | } | 594 | | | 595 | 11.1k | out.append(&c, sizeof(Chr)); | 596 | 11.1k | } | 597 | 1.73k | return no_err; | 598 | 1.73k | } |
|
599 | 47 | bool encode(FilterChar * &, FilterChar * &, FilterCharVector &) const { |
600 | 47 | return true; |
601 | 47 | } acommon::EncodeDirect<unsigned char>::encode(acommon::FilterChar*&, acommon::FilterChar*&, acommon::FilterCharVector&) const Line | Count | Source | 599 | 47 | bool encode(FilterChar * &, FilterChar * &, FilterCharVector &) const { | 600 | 47 | return true; | 601 | 47 | } |
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 |
602 | | }; |
603 | | |
604 | | template <typename Chr> |
605 | | struct ConvDirect : public DirectConv |
606 | | { |
607 | 38 | 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 | 607 | 38 | ConvDirect() {type_width = sizeof(Chr);} |
|
608 | 15.7k | void convert(const char * in0, int size, CharVector & out) const { |
609 | 15.7k | if (size == -sizeof(Chr)) { |
610 | 15.4k | const Chr * in = reinterpret_cast<const Chr *>(in0); |
611 | 64.2k | for (;*in != 0; ++in) |
612 | 48.8k | out.append(in, sizeof(Chr)); |
613 | 15.4k | } else if (size <= -1) { |
614 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); |
615 | 0 | abort(); |
616 | 278 | } else { |
617 | 278 | out.append(in0, size); |
618 | 278 | } |
619 | 15.7k | } 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 | 608 | 15.7k | void convert(const char * in0, int size, CharVector & out) const { | 609 | 15.7k | if (size == -sizeof(Chr)) { | 610 | 15.4k | const Chr * in = reinterpret_cast<const Chr *>(in0); | 611 | 64.2k | for (;*in != 0; ++in) | 612 | 48.8k | out.append(in, sizeof(Chr)); | 613 | 15.4k | } else if (size <= -1) { | 614 | 0 | fprintf(stderr, "%s\n", unsupported_null_term_wide_string_msg); | 615 | 0 | abort(); | 616 | 278 | } else { | 617 | 278 | out.append(in0, size); | 618 | 278 | } | 619 | 15.7k | } |
|
620 | | PosibErr<void> convert_ec(const char * in0, int size, |
621 | 0 | CharVector & out, ParmStr) const { |
622 | 0 | ConvDirect::convert(in0, size, out); |
623 | 0 | return no_err; |
624 | 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 |
625 | | }; |
626 | | |
627 | | ////////////////////////////////////////////////////////////////////// |
628 | | // |
629 | | // Lookup Conversion |
630 | | // |
631 | | |
632 | | struct DecodeLookup : public Decode |
633 | | { |
634 | | ToUniLookup lookup; |
635 | 23 | PosibErr<void> init(ParmStr code, const Config & c) { |
636 | 23 | FromUniLookup unused; |
637 | 23 | return read_in_char_data(c, code, lookup, unused); |
638 | 23 | } |
639 | 161 | void decode(const char * in, int size, FilterCharVector & out) const { |
640 | 161 | if (size == -1) { |
641 | 0 | for (;*in; ++in) |
642 | 0 | out.append(lookup[*in]); |
643 | 161 | } else { |
644 | 161 | const char * stop = in + size; |
645 | 1.43M | for (;in != stop; ++in) |
646 | 1.43M | out.append(lookup[*in]); |
647 | 161 | } |
648 | 161 | } |
649 | | PosibErr<void> decode_ec(const char * in, int size, |
650 | 0 | FilterCharVector & out, ParmStr) const { |
651 | 0 | DecodeLookup::decode(in, size, out); |
652 | 0 | return no_err; |
653 | 0 | } |
654 | | }; |
655 | | |
656 | | struct DecodeNormLookup : public Decode |
657 | | { |
658 | | typedef ToUniNormEntry E; |
659 | | NormTable<E> * data; |
660 | 6.32k | DecodeNormLookup(NormTable<E> * d) : data(d) {} |
661 | | // must be null terminated |
662 | | // FIXME: Why must it be null terminated? |
663 | 491k | void decode(const char * in, int size, FilterCharVector & out) const { |
664 | 491k | const char * stop = in + size; // will work even if size -1 |
665 | 2.73M | while (in != stop) { |
666 | 2.73M | if (*in == 0) { |
667 | 491k | if (size == -1) break; |
668 | 0 | out.append(0); |
669 | 0 | ++in; |
670 | 2.24M | } else { |
671 | 2.24M | NormLookupRet<E,const char> ret = norm_lookup<E>(data, in, stop, 0, in); |
672 | 4.49M | for (unsigned i = 0; i < E::max_to && ret.to[i]; ++i) |
673 | 2.24M | out.append(ret.to[i]); |
674 | 2.24M | in = ret.last + 1; |
675 | 2.24M | } |
676 | 2.73M | } |
677 | 491k | } |
678 | | PosibErr<void> decode_ec(const char * in, int size, |
679 | 0 | FilterCharVector & out, ParmStr) const { |
680 | 0 | DecodeNormLookup::decode(in, size, out); |
681 | 0 | return no_err; |
682 | 0 | } |
683 | | }; |
684 | | |
685 | | struct EncodeLookup : public Encode |
686 | | { |
687 | | FromUniLookup lookup; |
688 | | PosibErr<void> init(ParmStr code, const Config & c) |
689 | 17 | {ToUniLookup unused; |
690 | 17 | return read_in_char_data(c, code, unused, lookup);} |
691 | | void encode(const FilterChar * in, const FilterChar * stop, |
692 | 5.61k | CharVector & out) const { |
693 | 25.8k | for (; in != stop; ++in) { |
694 | 20.2k | out.append(lookup(*in)); |
695 | 20.2k | } |
696 | 5.61k | } |
697 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
698 | 0 | CharVector & out, ParmStr orig) const { |
699 | 0 | for (; in != stop; ++in) { |
700 | 0 | char c = lookup(*in, '\0'); |
701 | 0 | if (c == '\0' && in->chr != 0) { |
702 | 0 | char m[70]; |
703 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
704 | 0 | return make_err(invalid_string, orig, m); |
705 | 0 | } |
706 | 0 | out.append(c); |
707 | 0 | } |
708 | 0 | return no_err; |
709 | 0 | } |
710 | | bool encode(FilterChar * & in0, FilterChar * & stop, |
711 | 0 | FilterCharVector & out) const { |
712 | 0 | FilterChar * in = in0; |
713 | 0 | for (; in != stop; ++in) |
714 | 0 | *in = lookup(*in); |
715 | 0 | return true; |
716 | 0 | } |
717 | | }; |
718 | | |
719 | | struct EncodeNormLookup : public Encode |
720 | | { |
721 | | typedef FromUniNormEntry E; |
722 | | NormTable<E> * data; |
723 | 2.10k | EncodeNormLookup(NormTable<E> * d) : data(d) {} |
724 | | // *stop must equal 0 |
725 | | void encode(const FilterChar * in, const FilterChar * stop, |
726 | 8.82k | CharVector & out) const { |
727 | 14.7M | while (in < stop) { |
728 | 14.7M | if (*in == 0) { |
729 | 0 | out.append('\0'); |
730 | 0 | ++in; |
731 | 14.7M | } else { |
732 | 14.7M | NormLookupRet<E,const FilterChar> ret = norm_lookup<E>(data, in, stop, (const byte *)"?", in); |
733 | 29.6M | for (unsigned i = 0; i < E::max_to && ret.to[i]; ++i) |
734 | 14.8M | out.append(ret.to[i]); |
735 | 14.7M | in = ret.last + 1; |
736 | 14.7M | } |
737 | 14.7M | } |
738 | 8.82k | } |
739 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
740 | 16.0k | CharVector & out, ParmStr orig) const { |
741 | 48.0k | while (in < stop) { |
742 | 32.0k | if (*in == 0) { |
743 | 0 | out.append('\0'); |
744 | 0 | ++in; |
745 | 32.0k | } else { |
746 | 32.0k | NormLookupRet<E,const FilterChar> ret = norm_lookup<E>(data, in, stop, 0, in); |
747 | 32.0k | if (ret.to == 0) { |
748 | 0 | char m[70]; |
749 | 0 | snprintf(m, 70, _("The Unicode code point U+%04X is unsupported."), in->chr); |
750 | 0 | return make_err(invalid_string, orig, m); |
751 | 0 | } |
752 | 64.0k | for (unsigned i = 0; i < E::max_to && ret.to[i]; ++i) |
753 | 32.0k | out.append(ret.to[i]); |
754 | 32.0k | in = ret.last + 1; |
755 | 32.0k | } |
756 | 32.0k | } |
757 | 16.0k | return no_err; |
758 | 16.0k | } |
759 | | bool encode(FilterChar * & in, FilterChar * & stop, |
760 | 688 | FilterCharVector & buf) const { |
761 | 688 | buf.clear(); |
762 | 23.1M | while (in < stop) { |
763 | 23.1M | if (*in == 0) { |
764 | 1.30M | buf.append(FilterChar(0)); |
765 | 1.30M | ++in; |
766 | 21.8M | } else { |
767 | 21.8M | NormLookupRet<E,FilterChar> ret = norm_lookup<E>(data, in, stop, (const byte *)"?", in); |
768 | 21.8M | const FilterChar * end = ret.last + 1; |
769 | 21.8M | unsigned width = 0; |
770 | 43.7M | for (; in != end; ++in) width += in->width; |
771 | 21.8M | buf.append(FilterChar(ret.to[0], width)); |
772 | 21.8M | for (unsigned i = 1; i < E::max_to && ret.to[i]; ++i) { |
773 | 34.3k | buf.append(FilterChar(ret.to[i],0)); |
774 | 34.3k | } |
775 | 21.8M | } |
776 | 23.1M | } |
777 | 688 | buf.append(0); |
778 | 688 | in = buf.pbegin(); |
779 | 688 | stop = buf.pend(); |
780 | 688 | return true; |
781 | 688 | } |
782 | | }; |
783 | | |
784 | | ////////////////////////////////////////////////////////////////////// |
785 | | // |
786 | | // UTF8 |
787 | | // |
788 | | |
789 | | #define get_check_next \ |
790 | 592 | if (in == stop) goto error; \ |
791 | 592 | c = *in; \ |
792 | 592 | if ((c & 0xC0/*1100 0000*/) != 0x80/*10xx xxxx*/) goto error;\ |
793 | 592 | ++in; \ |
794 | 589 | u <<= 6; \ |
795 | 589 | u |= c & 0x3F/*0011 1111*/; \ |
796 | 589 | ++w; |
797 | | |
798 | | static inline FilterChar from_utf8 (const char * & in, const char * stop = 0, |
799 | | Uni32 err_char = '?') |
800 | 46.8k | { |
801 | 46.8k | Uni32 u = (Uni32)(-1); |
802 | 46.8k | FilterChar::Width w = 1; |
803 | | |
804 | | // the first char is guaranteed not to be off the end |
805 | 46.8k | char c = *in; |
806 | 46.8k | ++in; |
807 | | |
808 | 46.8k | if ((c & 0x80/*1000 0000*/) == 0x00/*0xxx xxx*/) { |
809 | 46.5k | u = c; |
810 | 46.5k | } else if ((c & 0xE0/*1110 0000*/) == 0xC0/*110x xxxx*/) { // 2-byte wide |
811 | 154 | u = c & 0x1F/*0001 1111*/; |
812 | 305 | get_check_next; |
813 | 305 | } else if ((c & 0xF0/*1111 0000*/) == 0xE0/*1110 xxxx*/) { // 3-byte wide |
814 | 120 | u = c & 0x0F/*0000 1111*/; |
815 | 240 | get_check_next; |
816 | 240 | get_check_next; |
817 | 240 | } else if ((c & 0xF8/*1111 1000*/) == 0xF0/*1111 0xxx*/) { // 4-byte wide |
818 | 66 | u = c & 0x07/*0000 0111*/; |
819 | 132 | get_check_next; |
820 | 132 | get_check_next; |
821 | 132 | get_check_next; |
822 | 132 | } else { |
823 | 1 | goto error; |
824 | 1 | } |
825 | | |
826 | 46.8k | return FilterChar(u, w); |
827 | 4 | error: |
828 | 4 | return FilterChar(err_char, w); |
829 | 46.8k | } |
830 | | |
831 | | static inline void to_utf8 (FilterChar in, CharVector & out) |
832 | 0 | { |
833 | 0 | FilterChar::Chr c = in; |
834 | | |
835 | 0 | if (c < 0x80) { |
836 | 0 | out.append(c); |
837 | 0 | } |
838 | 0 | else if (c < 0x800) { |
839 | 0 | out.append(0xC0 | (c>>6)); |
840 | 0 | out.append(0x80 | (c & 0x3F)); |
841 | 0 | } |
842 | 0 | else if (c < 0x10000) { |
843 | 0 | out.append(0xE0 | (c>>12)); |
844 | 0 | out.append(0x80 | (c>>6 & 0x3F)); |
845 | 0 | out.append(0x80 | (c & 0x3F)); |
846 | 0 | } |
847 | 0 | else if (c < 0x200000) { |
848 | 0 | out.append(0xF0 | (c>>18)); |
849 | 0 | out.append(0x80 | (c>>12 & 0x3F)); |
850 | 0 | out.append(0x80 | (c>>6 & 0x3F)); |
851 | 0 | out.append(0x80 | (c & 0x3F)); |
852 | 0 | } |
853 | 0 | } |
854 | | |
855 | | struct DecodeUtf8 : public Decode |
856 | | { |
857 | | ToUniLookup lookup; |
858 | 0 | void decode(const char * in, int size, FilterCharVector & out) const { |
859 | 0 | if (size == -1) { |
860 | 0 | while (*in) |
861 | 0 | out.append(from_utf8(in)); |
862 | 0 | } else { |
863 | 0 | const char * stop = in + size; |
864 | 0 | while (in != stop) |
865 | 0 | out.append(from_utf8(in, stop)); |
866 | 0 | } |
867 | 0 | } |
868 | | PosibErr<void> decode_ec(const char * in, int size, |
869 | 18.8k | FilterCharVector & out, ParmStr orig) const { |
870 | 18.8k | const char * begin = in; |
871 | 18.8k | if (size == -1) { |
872 | 14.3k | while (*in) { |
873 | 12.6k | FilterChar c = from_utf8(in, 0, (Uni32)-1); |
874 | 12.6k | if (c == (Uni32)-1) goto error; |
875 | 12.6k | out.append(c); |
876 | 12.6k | } |
877 | 17.1k | } else { |
878 | 17.1k | const char * stop = in + size; |
879 | 51.3k | while (in != stop) { |
880 | 34.2k | FilterChar c = from_utf8(in, stop, (Uni32)-1); |
881 | 34.2k | if (c == (Uni32)-1) goto error; |
882 | 34.2k | out.append(c); |
883 | 34.2k | } |
884 | 17.1k | } |
885 | 18.8k | return no_err; |
886 | 4 | error: |
887 | 4 | char m[70]; |
888 | 4 | snprintf(m, 70, _("Invalid UTF-8 sequence at position %ld."), (long)(in - begin)); |
889 | 4 | return make_err(invalid_string, orig, m); |
890 | 18.8k | } |
891 | | }; |
892 | | |
893 | | struct EncodeUtf8 : public Encode |
894 | | { |
895 | | FromUniLookup lookup; |
896 | | void encode(const FilterChar * in, const FilterChar * stop, |
897 | 0 | CharVector & out) const { |
898 | 0 | for (; in != stop; ++in) { |
899 | 0 | to_utf8(*in, out); |
900 | 0 | } |
901 | 0 | } |
902 | | PosibErr<void> encode_ec(const FilterChar * in, const FilterChar * stop, |
903 | 0 | CharVector & out, ParmStr) const { |
904 | 0 | for (; in != stop; ++in) { |
905 | 0 | to_utf8(*in, out); |
906 | 0 | } |
907 | 0 | return no_err; |
908 | 0 | } |
909 | | }; |
910 | | |
911 | | ////////////////////////////////////////////////////////////////////// |
912 | | // |
913 | | // Cache |
914 | | // |
915 | | |
916 | | static GlobalCache<Decode> decode_cache("decode"); |
917 | | static GlobalCache<Encode> encode_cache("encode"); |
918 | | static GlobalCache<NormTables> norm_tables_cache("norm_tables"); |
919 | | |
920 | | ////////////////////////////////////////////////////////////////////// |
921 | | // |
922 | | // new_aspell_convert |
923 | | // |
924 | | |
925 | | void Convert::generic_convert(const char * in, int size, CharVector & out) |
926 | 1.78k | { |
927 | 1.78k | buf_.clear(); |
928 | 1.78k | decode_->decode(in, size, buf_); |
929 | 1.78k | FilterChar * start = buf_.pbegin(); |
930 | 1.78k | FilterChar * stop = buf_.pend(); |
931 | 1.78k | if (!filter.empty()) |
932 | 1.78k | filter.process(start, stop); |
933 | 1.78k | encode_->encode(start, stop, out); |
934 | 1.78k | } |
935 | | |
936 | | const char * fix_encoding_str(ParmStr enc, String & buf) |
937 | 32.3k | { |
938 | 32.3k | buf.clear(); |
939 | 32.3k | buf.reserve(enc.size() + 1); |
940 | 320k | for (size_t i = 0; i != enc.size(); ++i) |
941 | 288k | buf.push_back(asc_tolower(enc[i])); |
942 | | |
943 | 32.3k | if (strncmp(buf.c_str(), "iso8859", 7) == 0) |
944 | 2.24k | buf.insert(buf.begin() + 3, '-'); // For backwards compatibility |
945 | | |
946 | 32.3k | if (buf == "ascii" || buf == "ansi_x3.4-1968") |
947 | 0 | return "iso-8859-1"; |
948 | 32.3k | else if (buf == "machine unsigned 16" || buf == "utf-16") |
949 | 32 | return "ucs-2"; |
950 | 32.3k | else if (buf == "machine unsigned 32" || buf == "utf-32") |
951 | 136 | return "ucs-4"; |
952 | 32.1k | else |
953 | 32.1k | return buf.c_str(); |
954 | 32.3k | } |
955 | | |
956 | | bool ascii_encoding(const Config & c, ParmStr enc0) |
957 | 1.75k | { |
958 | 1.75k | if (enc0.empty()) return true; |
959 | 1.75k | if (enc0 == "ANSI_X3.4-1968" |
960 | 1.75k | || enc0 == "ASCII" || enc0 == "ascii") return true; |
961 | 0 | String buf; |
962 | 0 | const char * enc = fix_encoding_str(enc0, buf); |
963 | 0 | if (strcmp(enc, "utf-8") == 0 |
964 | 0 | || strcmp(enc, "ucs-2") == 0 |
965 | 0 | || strcmp(enc, "ucs-4") == 0) return false; |
966 | 0 | String dir1,dir2,file_name; |
967 | 0 | fill_data_dir(&c, dir1, dir2); |
968 | 0 | file_name << dir1 << enc << ".cset"; |
969 | 0 | if (file_exists(file_name)) return false; |
970 | 0 | if (dir1 == dir2) return true; |
971 | 0 | file_name.clear(); |
972 | 0 | file_name << dir2 << enc << ".cset"; |
973 | 0 | return !file_exists(file_name); |
974 | 0 | } |
975 | | |
976 | | PosibErr<Convert *> internal_new_convert(const Config & c, |
977 | | ConvKey in, |
978 | | ConvKey out, |
979 | | bool if_needed, |
980 | | Normalize norm) |
981 | 15.0k | { |
982 | 15.0k | String in_s; |
983 | 15.0k | in.val = fix_encoding_str(in.val, in_s); |
984 | | |
985 | 15.0k | String out_s; |
986 | 15.0k | out.val = fix_encoding_str(out.val, out_s); |
987 | | |
988 | 15.0k | if (if_needed && in.val == out.val) return 0; |
989 | | |
990 | 9.02k | StackPtr<Convert> conv(new Convert); |
991 | 9.02k | switch (norm) { |
992 | 27 | case NormNone: |
993 | 27 | RET_ON_ERR(conv->init(c, in, out)); break; |
994 | 2.25k | case NormFrom: |
995 | 2.25k | RET_ON_ERR(conv->init_norm_from(c, in, out)); break; |
996 | 6.73k | case NormTo: |
997 | 6.73k | RET_ON_ERR(conv->init_norm_to(c, in, out)); break; |
998 | 9.02k | } |
999 | 9.01k | return conv.release(); |
1000 | 9.02k | } |
1001 | | |
1002 | | PosibErr<Decode *> Decode::get_new(const ConvKey & k, const Config * c) |
1003 | 1.53k | { |
1004 | 1.53k | StackPtr<Decode> ptr; |
1005 | 1.53k | if (k.val == "iso-8859-1") { |
1006 | 675 | ptr.reset(new DecodeDirect<Uni8>); |
1007 | 861 | } else if (k.val == "ucs-2") { |
1008 | 16 | if (k.allow_ucs) |
1009 | 16 | ptr.reset(new DecodeDirect<Uni16>); |
1010 | 0 | else |
1011 | 0 | return make_err(encoding_not_supported, k.val); |
1012 | 845 | } else if (k.val == "ucs-4") { |
1013 | 68 | if (k.allow_ucs) |
1014 | 68 | ptr.reset(new DecodeDirect<Uni32>); |
1015 | 0 | else |
1016 | 0 | return make_err(encoding_not_supported, k.val); |
1017 | 777 | } else if (k.val == "utf-8") { |
1018 | 754 | ptr.reset(new DecodeUtf8); |
1019 | 754 | } else { |
1020 | 23 | ptr.reset(new DecodeLookup); |
1021 | 23 | } |
1022 | 1.53k | RET_ON_ERR(ptr->init(k.val, *c)); |
1023 | 1.53k | ptr->key = k.val; |
1024 | 1.53k | return ptr.release(); |
1025 | 1.53k | } |
1026 | | |
1027 | | PosibErr<Encode *> Encode::get_new(const ConvKey & k, const Config * c) |
1028 | 1.55k | { |
1029 | 1.55k | StackPtr<Encode> ptr; |
1030 | 1.55k | if (k.val == "iso-8859-1") { |
1031 | 675 | ptr.reset(new EncodeDirect<Uni8>); |
1032 | 882 | } else if (k.val == "ucs-2" && k.allow_ucs) { |
1033 | 16 | if (k.allow_ucs) |
1034 | 16 | ptr.reset(new EncodeDirect<Uni16>); |
1035 | 0 | else |
1036 | 0 | return make_err(encoding_not_supported, k.val); |
1037 | 866 | } else if (k.val == "ucs-4" && k.allow_ucs) { |
1038 | 95 | if (k.allow_ucs) |
1039 | 95 | ptr.reset(new EncodeDirect<Uni32>); |
1040 | 0 | else |
1041 | 0 | return make_err(encoding_not_supported, k.val); |
1042 | 771 | } else if (k.val == "utf-8") { |
1043 | 754 | ptr.reset(new EncodeUtf8); |
1044 | 754 | } else { |
1045 | 17 | ptr.reset(new EncodeLookup); |
1046 | 17 | } |
1047 | 1.55k | RET_ON_ERR(ptr->init(k.val, *c)); |
1048 | 1.55k | ptr->key = k.val; |
1049 | 1.55k | return ptr.release(); |
1050 | 1.55k | } |
1051 | | |
1052 | 9.02k | Convert::~Convert() {} |
1053 | | |
1054 | | PosibErr<void> Convert::init(const Config & c, const ConvKey & in, const ConvKey & out) |
1055 | 583 | { |
1056 | 583 | RET_ON_ERR(setup(decode_c, &decode_cache, &c, in)); |
1057 | 583 | decode_ = decode_c.get(); |
1058 | 583 | RET_ON_ERR(setup(encode_c, &encode_cache, &c, out)); |
1059 | 583 | encode_ = encode_c.get(); |
1060 | | |
1061 | 583 | conv_ = 0; |
1062 | 583 | if (in.val == out.val) { |
1063 | 38 | if (in.val == "ucs-2") { |
1064 | 0 | if (in.allow_ucs) { |
1065 | 0 | conv_ = new ConvDirect<Uni16>; |
1066 | 0 | } else { |
1067 | 0 | return make_err(encoding_not_supported, in.val); |
1068 | 0 | } |
1069 | 38 | } else if (in.val == "ucs-4") { |
1070 | 0 | if (in.allow_ucs) { |
1071 | 0 | conv_ = new ConvDirect<Uni32>; |
1072 | 0 | } else { |
1073 | 0 | return make_err(encoding_not_supported, in.val); |
1074 | 0 | } |
1075 | 38 | } else { |
1076 | 38 | conv_ = new ConvDirect<char>; |
1077 | 38 | } |
1078 | 38 | } |
1079 | | |
1080 | 583 | if (conv_) |
1081 | 38 | RET_ON_ERR(conv_->init(decode_, encode_, c)); |
1082 | | |
1083 | 583 | return no_err; |
1084 | 583 | } |
1085 | | |
1086 | | |
1087 | | PosibErr<void> Convert::init_norm_from(const Config & c, const ConvKey & in, const ConvKey & out) |
1088 | 2.25k | { |
1089 | 2.25k | if (!c.retrieve_bool("normalize") && !c.retrieve_bool("norm-required")) |
1090 | 141 | return init(c,in,out); |
1091 | | |
1092 | 2.11k | RET_ON_ERR(setup(norm_tables_, &norm_tables_cache, &c, out.val)); |
1093 | | |
1094 | 2.11k | RET_ON_ERR(setup(decode_c, &decode_cache, &c, in)); |
1095 | 2.10k | decode_ = decode_c.get(); |
1096 | | |
1097 | 2.10k | if (c.retrieve_bool("norm-strict")) { |
1098 | 9 | encode_s = new EncodeNormLookup(norm_tables_->strict); |
1099 | 9 | encode_ = encode_s; |
1100 | 9 | encode_->key = out.val; |
1101 | 9 | encode_->key += ":strict"; |
1102 | 2.10k | } else { |
1103 | 2.10k | encode_s = new EncodeNormLookup(norm_tables_->internal); |
1104 | 2.10k | encode_ = encode_s; |
1105 | 2.10k | encode_->key = out.val; |
1106 | 2.10k | encode_->key += ":internal"; |
1107 | 2.10k | } |
1108 | 2.10k | conv_ = 0; |
1109 | | |
1110 | 2.10k | return no_err; |
1111 | 2.11k | } |
1112 | | |
1113 | | PosibErr<void> Convert::init_norm_to(const Config & c, const ConvKey & in, const ConvKey & out) |
1114 | 6.73k | { |
1115 | 6.73k | String norm_form = c.retrieve("norm-form"); |
1116 | 6.73k | if ((!c.retrieve_bool("normalize") || norm_form == "none") |
1117 | 415 | && !c.retrieve_bool("norm-required")) |
1118 | 415 | return init(c,in,out); |
1119 | 6.32k | if (norm_form == "none" && c.retrieve_bool("norm-required")) |
1120 | 0 | norm_form = "nfc"; |
1121 | | |
1122 | 6.32k | RET_ON_ERR(setup(norm_tables_, &norm_tables_cache, &c, in.val)); |
1123 | | |
1124 | 6.32k | RET_ON_ERR(setup(encode_c, &encode_cache, &c, out)); |
1125 | 6.32k | encode_ = encode_c.get(); |
1126 | | |
1127 | 6.32k | NormTables::ToUni::const_iterator i = norm_tables_->to_uni.begin(); |
1128 | 12.6k | for (; i != norm_tables_->to_uni.end() && i->name != norm_form; ++i); |
1129 | 6.32k | if (i == norm_tables_->to_uni.end()) |
1130 | 0 | return make_err(aerror_bad_value, "norm-form", norm_form, "one of none, nfd, nfc, or comp"); |
1131 | | |
1132 | 6.32k | decode_s = new DecodeNormLookup(i->ptr); |
1133 | 6.32k | decode_ = decode_s; |
1134 | 6.32k | decode_->key = in.val; |
1135 | 6.32k | decode_->key += ':'; |
1136 | 6.32k | decode_->key += i->name; |
1137 | | |
1138 | 6.32k | conv_ = 0; |
1139 | | |
1140 | 6.32k | return no_err; |
1141 | 6.32k | } |
1142 | | |
1143 | | PosibErr<void> MBLen::setup(const Config &, ParmStr enc0) |
1144 | 0 | { |
1145 | 0 | String buf; |
1146 | 0 | const char * enc = fix_encoding_str(enc0,buf); |
1147 | 0 | if (strcmp(enc, "utf-8") == 0) encoding = UTF8; |
1148 | 0 | else if (strcmp(enc, "ucs-2") == 0) encoding = UCS2; |
1149 | 0 | else if (strcmp(enc, "ucs-4") == 0) encoding = UCS4; |
1150 | 0 | else encoding = Other; |
1151 | 0 | return no_err; |
1152 | 0 | } |
1153 | | |
1154 | | unsigned MBLen::operator()(const char * str, const char * stop) |
1155 | 0 | { |
1156 | 0 | unsigned size = 0; |
1157 | 0 | switch (encoding) { |
1158 | 0 | case Other: |
1159 | 0 | return stop - str; |
1160 | 0 | case UTF8: |
1161 | 0 | for (; str != stop; ++str) { |
1162 | 0 | if ((*str & 0x80) == 0 || (*str & 0xC0) == 0xC0) ++size; |
1163 | 0 | } |
1164 | 0 | return size; |
1165 | 0 | case UCS2: |
1166 | 0 | return (stop - str)/2; |
1167 | 0 | case UCS4: |
1168 | 0 | return (stop - str)/4; |
1169 | 0 | } |
1170 | 0 | return 0; |
1171 | 0 | } |
1172 | | |
1173 | 0 | PosibErr<void> unsupported_null_term_wide_string_err_(const char * func) { |
1174 | 0 | static bool reported_to_stderr = false; |
1175 | 0 | PosibErr<void> err = make_err(other_error, unsupported_null_term_wide_string_msg); |
1176 | 0 | if (!reported_to_stderr) { |
1177 | 0 | CERR.printf("ERROR: %s: %s\n", func, unsupported_null_term_wide_string_msg); |
1178 | 0 | reported_to_stderr = true; |
1179 | 0 | } |
1180 | 0 | return err; |
1181 | 0 | } |
1182 | | |
1183 | 0 | void unsupported_null_term_wide_string_abort_(const char * func) { |
1184 | 0 | CERR.printf("%s: %s\n", func, unsupported_null_term_wide_string_msg); |
1185 | 0 | abort(); |
1186 | 0 | } |
1187 | | |
1188 | | } |