Imported Upstream version 0.66.1
[hcoop/debian/courier-authlib.git] / libs / unicode / unicodecpp.C
1 /*
2 ** Copyright 2011 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 **
5 */
6
7 #include "unicode_config.h"
8 #include "unicode.h"
9
10 extern "C" {
11
12 static int iconv_trampoline(const char *str, size_t cnt, void *arg)
13 {
14 return reinterpret_cast<mail::iconvert *>(arg)
15 ->converted(str, cnt);
16 }
17
18 int mail::linebreak_trampoline(int value, void *ptr)
19 {
20 return (*reinterpret_cast<mail::linebreak_callback_base *>
21 (ptr))(value);
22 }
23
24 int mail::linebreakc_trampoline(int value, unicode_char ch, void *ptr)
25 {
26 return (*reinterpret_cast<mail::linebreakc_callback_base *>
27 (ptr))(value, ch);
28 }
29
30 int mail::wordbreak_trampoline(int value, void *ptr)
31 {
32 return (*reinterpret_cast<mail::wordbreak_callback_base *>
33 (ptr))(value != 0);
34 }
35
36 }
37
38 size_t unicode_wcwidth(const std::vector<unicode_char> &uc)
39 {
40 size_t w=0;
41
42 for (std::vector<unicode_char>::const_iterator
43 b(uc.begin()), e(uc.end()); b != e; ++b)
44 w += unicode_wcwidth(*b);
45 return w;
46 }
47
48 mail::iconvert::iconvert() : handle(NULL)
49 {
50 }
51
52 mail::iconvert::~iconvert()
53 {
54 end();
55 }
56
57 int mail::iconvert::converted(const char *, size_t)
58 {
59 return 0;
60 }
61
62 bool mail::iconvert::begin(const std::string &src_chset,
63 const std::string &dst_chset)
64 {
65 end();
66
67 if ((handle=libmail_u_convert_init(src_chset.c_str(),
68 dst_chset.c_str(),
69 &iconv_trampoline,
70 this)) == NULL)
71 return false;
72 return true;
73 }
74
75 bool mail::iconvert::end(bool *errflag)
76 {
77 int errptr;
78
79 int rc;
80
81 if (!handle)
82 return true;
83
84 rc=libmail_u_convert_deinit(handle, &errptr);
85 handle=NULL;
86
87 if (errflag)
88 *errflag=errptr != 0;
89 return rc == 0;
90 }
91
92 bool mail::iconvert::operator()(const char *str, size_t cnt)
93 {
94 if (!handle)
95 return false;
96
97 return (libmail_u_convert(handle, str, cnt) == 0);
98 }
99
100 bool mail::iconvert::operator()(const unicode_char *str, size_t cnt)
101 {
102 if (!handle)
103 return false;
104
105 return (libmail_u_convert_uc(handle, str, cnt) == 0);
106 }
107
108 std::string mail::iconvert::convert(const std::string &text,
109 const std::string &charset,
110 const std::string &dstcharset,
111 bool &errflag)
112 {
113 std::string buf;
114 int errptr;
115
116 char *p=libmail_u_convert_tobuf(text.c_str(),
117 charset.c_str(),
118 dstcharset.c_str(),
119 &errptr);
120
121 errflag= errptr != 0;
122
123 try {
124 buf=p;
125 free(p);
126 } catch (...) {
127 free(p);
128 throw;
129 }
130
131 return buf;
132 }
133
134
135 std::string mail::iconvert::convert(const std::vector<unicode_char> &uc,
136 const std::string &dstcharset,
137 bool &errflag)
138 {
139 std::string buf;
140
141 char *c;
142 size_t csize;
143 int err;
144
145 if (libmail_u_convert_fromu_tobuf(&uc[0], uc.size(),
146 dstcharset.c_str(), &c, &csize,
147 &err))
148 {
149 err=1;
150 }
151 else
152 {
153 if (csize)
154 --csize; // Trailing NULL
155 try {
156 buf.append(c, c+csize);
157 free(c);
158 } catch (...)
159 {
160 free(c);
161 throw;
162 }
163 }
164
165 errflag= err != 0;
166
167 return buf;
168 }
169
170 bool mail::iconvert::convert(const std::string &text,
171 const std::string &charset,
172 std::vector<unicode_char> &uc)
173 {
174 int err;
175
176 unicode_char *ucbuf;
177 size_t ucsize;
178
179 if (libmail_u_convert_tou_tobuf(text.c_str(),
180 text.size(),
181 charset.c_str(),
182 &ucbuf,
183 &ucsize,
184 &err))
185 return false;
186
187 try {
188 uc.clear();
189 uc.reserve(ucsize);
190 uc.insert(uc.end(), ucbuf, ucbuf+ucsize);
191 free(ucbuf);
192 } catch (...)
193 {
194 free(ucbuf);
195 throw;
196 }
197
198 return err == 0;
199 }
200
201 int mail::iconvert::tou::converted(const unicode_char *, size_t)
202 {
203 return 0;
204 }
205
206 bool mail::iconvert::tou::begin(const std::string &chset)
207 {
208 return iconvert::begin(chset, libmail_u_ucs4_native);
209 }
210
211 int mail::iconvert::tou::converted(const char *ptr, size_t cnt)
212 {
213 return converted(reinterpret_cast<const unicode_char *>(ptr),
214 cnt/sizeof(unicode_char));
215 }
216
217 void mail::iconvert::tou::convert(const std::string &str,
218 const std::string &chset,
219 std::vector<unicode_char> &out_buf)
220 {
221 convert(str.begin(), str.end(), chset, out_buf);
222 }
223
224 bool mail::iconvert::fromu::begin(const std::string &chset)
225 {
226 return iconvert::begin(libmail_u_ucs4_native, chset);
227 }
228
229 std::string mail::iconvert::fromu::convert(const std::vector<unicode_char>
230 &ubuf,
231 const std::string &chset)
232 {
233 std::string s;
234
235 convert(ubuf, chset, s);
236 return s;
237 }
238
239 void mail::iconvert::fromu::convert(const std::vector<unicode_char> &ubuf,
240 const std::string &chset,
241 std::string &out_buf)
242 {
243 convert(ubuf.begin(), ubuf.end(), chset, out_buf);
244 }
245
246 std::string mail::iconvert::convert_tocase(const std::string &text,
247 const std::string &charset,
248 bool &err,
249 unicode_char (*first_char_func)(unicode_char),
250 unicode_char (*char_func)(unicode_char))
251 {
252 err=false;
253 std::string s;
254
255 char *p=libmail_u_convert_tocase(text.c_str(),
256 charset.c_str(),
257 first_char_func,
258 char_func);
259
260 if (!p)
261 {
262 err=true;
263 return s;
264 }
265
266 try {
267 s=p;
268 free(p);
269 } catch (...) {
270 free(p);
271 throw;
272 }
273 return s;
274 }
275
276 mail::linebreak_callback_base::linebreak_callback_base()
277 : handle(NULL), opts(0)
278 {
279 }
280
281
282 void mail::linebreak_callback_base::set_opts(int optsArg)
283 {
284 opts=optsArg;
285
286 if (handle)
287 unicode_lb_set_opts(handle, opts);
288 }
289
290 mail::linebreak_callback_base::~linebreak_callback_base()
291 {
292 finish();
293 }
294
295 int mail::linebreak_callback_base::operator()(int)
296 {
297 return 0;
298 }
299
300 mail::linebreak_callback_base
301 &mail::linebreak_callback_base::operator<<(unicode_char uc)
302 {
303 if (!handle)
304 {
305 handle=unicode_lb_init(linebreak_trampoline,
306 reinterpret_cast<void *>
307 (static_cast<linebreak_callback_base *>
308 (this)));
309 set_opts(opts);
310 }
311
312 if (handle)
313 if (unicode_lb_next(handle, uc))
314 finish();
315 return *this;
316 }
317
318 void mail::linebreak_callback_base::finish()
319 {
320 if (handle)
321 unicode_lb_end(handle);
322 handle=NULL;
323 }
324
325
326 mail::linebreak_callback_save_buf::linebreak_callback_save_buf()
327 {
328 }
329
330 mail::linebreak_callback_save_buf::~linebreak_callback_save_buf()
331 {
332 }
333
334 int mail::linebreak_callback_save_buf::operator()(int value)
335 {
336 lb_buf.push_back(value);
337 return 0;
338 }
339
340 mail::linebreakc_callback_base::linebreakc_callback_base()
341 : handle(NULL), opts(0)
342 {
343 }
344
345 mail::linebreakc_callback_base::~linebreakc_callback_base()
346 {
347 finish();
348 }
349
350 int mail::linebreakc_callback_base::operator()(int, unicode_char)
351 {
352 return 0;
353 }
354
355 void mail::linebreakc_callback_base::set_opts(int optsArg)
356 {
357 opts=optsArg;
358
359 if (handle)
360 unicode_lbc_set_opts(handle, opts);
361 }
362
363 mail::linebreakc_callback_base
364 &mail::linebreakc_callback_base::operator<<(unicode_char uc)
365 {
366 if (handle == NULL)
367 {
368 handle=unicode_lbc_init(linebreakc_trampoline,
369 reinterpret_cast<void *>
370 (static_cast<linebreakc_callback_base *>
371 (this)));
372 set_opts(opts);
373 }
374
375 if (handle)
376 if (unicode_lbc_next(handle, uc))
377 finish();
378 return *this;
379 }
380
381 void mail::linebreakc_callback_base::finish()
382 {
383 if (handle)
384 unicode_lbc_end(handle);
385 handle=NULL;
386 }
387
388
389 mail::linebreakc_callback_save_buf::linebreakc_callback_save_buf()
390 {
391 }
392
393 mail::linebreakc_callback_save_buf::~linebreakc_callback_save_buf()
394 {
395 }
396
397 int mail::linebreakc_callback_save_buf::operator()(int c, unicode_char ch)
398 {
399 lb_buf.push_back(std::make_pair(c, ch));
400 return 0;
401 }
402
403 mail::wordbreak_callback_base::wordbreak_callback_base()
404 : handle(NULL)
405 {
406 }
407
408 mail::wordbreak_callback_base::~wordbreak_callback_base()
409 {
410 finish();
411 }
412
413 int mail::wordbreak_callback_base::operator()(bool)
414 {
415 return 0;
416 }
417
418 mail::wordbreak_callback_base
419 &mail::wordbreak_callback_base::operator<<(unicode_char uc)
420 {
421 if (!handle)
422 {
423 handle=unicode_wb_init(wordbreak_trampoline,
424 reinterpret_cast<void *>
425 (static_cast<wordbreak_callback_base *>
426 (this)));
427 }
428
429 if (handle)
430 if (unicode_wb_next(handle, uc))
431 finish();
432 return *this;
433 }
434
435 void mail::wordbreak_callback_base::finish()
436 {
437 if (handle)
438 unicode_wb_end(handle);
439 handle=NULL;
440 }
441
442 /* -------------------------------------------- */
443
444 mail::wordbreakscan::wordbreakscan() : handle(NULL)
445 {
446 }
447
448 mail::wordbreakscan::~wordbreakscan()
449 {
450 finish();
451 }
452
453 bool mail::wordbreakscan::operator<<(unicode_char uc)
454 {
455 if (!handle)
456 handle=unicode_wbscan_init();
457
458 if (handle)
459 return unicode_wbscan_next(handle, uc) != 0;
460
461 return false;
462 }
463
464 size_t mail::wordbreakscan::finish()
465 {
466 size_t n=0;
467
468 if (handle)
469 {
470 n=unicode_wbscan_end(handle);
471 handle=NULL;
472 }
473 return n;
474 }