xref: /PHP-5.5/ext/mbstring/libmbfl/mbfl/mbfilter.c (revision f8dd1050)
1 /*
2  * charset=UTF-8
3  * vim600: encoding=utf-8
4  */
5 
6 /*
7  * "streamable kanji code filter and converter"
8  *
9  * Copyright (c) 1998,1999,2000,2001 HappySize, Inc. All rights reserved.
10  *
11  * This software is released under the GNU Lesser General Public License.
12  * (Version 2.1, February 1999)
13  * Please read the following detail of the licence (in japanese).
14  *
15  * ◆使用許諾条件◆
16  *
17  * このソフトウェアは株式会社ハッピーサイズによって開発されました。株式会社ハッ
18  * ピーサイズは、著作権法および万国著作権条約の定めにより、このソフトウェアに関
19  * するすべての権利を留保する権利を持ち、ここに行使します。株式会社ハッピーサイ
20  * ズは以下に明記した条件に従って、このソフトウェアを使用する排他的ではない権利
21  * をお客様に許諾します。何人たりとも、以下の条件に反してこのソフトウェアを使用
22  * することはできません。
23  *
24  * このソフトウェアを「GNU Lesser General Public License (Version 2.1, February
25  * 1999)」に示された条件で使用することを、全ての方に許諾します。「GNU Lesser
26  * General Public License」を満たさない使用には、株式会社ハッピーサイズから書面
27  * による許諾を得る必要があります。
28  *
29  * 「GNU Lesser General Public License」の全文は以下のウェブページから取得でき
30  * ます。「GNU Lesser General Public License」とは、これまでLibrary General
31  * Public Licenseと呼ばれていたものです。
32  *     http://www.gnu.org/ --- GNUウェブサイト
33  *     http://www.gnu.org/copyleft/lesser.html --- ライセンス文面
34  * このライセンスの内容がわからない方、守れない方には使用を許諾しません。
35  *
36  * しかしながら、当社とGNUプロジェクトとの特定の関係を示唆または主張するもので
37  * はありません。
38  *
39  * ◆保証内容◆
40  *
41  * このソフトウェアは、期待された動作・機能・性能を持つことを目標として設計され
42  * 開発されていますが、これを保証するものではありません。このソフトウェアは「こ
43  * のまま」の状態で提供されており、たとえばこのソフトウェアの有用性ないし特定の
44  * 目的に合致することといった、何らかの保証内容が、明示されたり暗黙に示されてい
45  * る場合であっても、その保証は無効です。このソフトウェアを使用した結果ないし使
46  * 用しなかった結果によって、直接あるいは間接に受けた身体的な傷害、財産上の損害
47  * 、データの損失あるいはその他の全ての損害については、その損害の可能性が使用者
48  * 、当社あるいは第三者によって警告されていた場合であっても、当社はその損害の賠
49  * 償および補填を行いません。この規定は他の全ての、書面上または書面に無い保証・
50  * 契約・規定に優先します。
51  *
52  * ◆著作権者の連絡先および使用条件についての問い合わせ先◆
53  *
54  * 〒102-0073
55  * 東京都千代田区九段北1-13-5日本地所第一ビル4F
56  * 株式会社ハッピーサイズ
57  * Phone: 03-3512-3655, Fax: 03-3512-3656
58  * Email: sales@happysize.co.jp
59  * Web: http://happysize.com/
60  *
61  * ◆著者◆
62  *
63  * 金本 茂 <sgk@happysize.co.jp>
64  *
65  * ◆履歴◆
66  *
67  * 1998/11/10 sgk implementation in C++
68  * 1999/4/25  sgk Cで書きなおし。
69  * 1999/4/26  sgk 入力フィルタを実装。漢字コードを推定しながらフィルタを追加。
70  * 1999/6/??      Unicodeサポート。
71  * 1999/6/22  sgk ライセンスをLGPLに変更。
72  *
73  */
74 
75 /*
76  * Unicode support
77  *
78  * Portions copyright (c) 1999,2000,2001 by the PHP3 internationalization team.
79  * All rights reserved.
80  *
81  */
82 
83 
84 #ifdef HAVE_CONFIG_H
85 #include "config.h"
86 #endif
87 
88 #include <stddef.h>
89 
90 #ifdef HAVE_STRING_H
91 #include <string.h>
92 #endif
93 
94 #ifdef HAVE_STRINGS_H
95 #include <strings.h>
96 #endif
97 
98 #ifdef HAVE_STDDEF_H
99 #include <stddef.h>
100 #endif
101 
102 #include "mbfilter.h"
103 #include "mbfl_filter_output.h"
104 #include "mbfilter_pass.h"
105 #include "filters/mbfilter_tl_jisx0201_jisx0208.h"
106 
107 #include "eaw_table.h"
108 
109 /* hex character table "0123456789ABCDEF" */
110 static char mbfl_hexchar_table[] = {
111 	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
112 };
113 
114 
115 
116 /*
117  * encoding filter
118  */
119 #define CK(statement)	do { if ((statement) < 0) return (-1); } while (0)
120 
121 
122 /*
123  *  buffering converter
124  */
125 mbfl_buffer_converter *
mbfl_buffer_converter_new(enum mbfl_no_encoding from,enum mbfl_no_encoding to,int buf_initsz)126 mbfl_buffer_converter_new(
127     enum mbfl_no_encoding from,
128     enum mbfl_no_encoding to,
129     int buf_initsz)
130 {
131 	const mbfl_encoding *_from = mbfl_no2encoding(from);
132 	const mbfl_encoding *_to = mbfl_no2encoding(to);
133 
134 	return mbfl_buffer_converter_new2(_from ? _from: &mbfl_encoding_pass, _to ? _to: &mbfl_encoding_pass, buf_initsz);
135 }
136 
137 mbfl_buffer_converter *
mbfl_buffer_converter_new2(const mbfl_encoding * from,const mbfl_encoding * to,int buf_initsz)138 mbfl_buffer_converter_new2(
139 	const mbfl_encoding *from,
140 	const mbfl_encoding *to,
141     int buf_initsz)
142 {
143 	mbfl_buffer_converter *convd;
144 
145 	/* allocate */
146 	convd = (mbfl_buffer_converter*)mbfl_malloc(sizeof (mbfl_buffer_converter));
147 	if (convd == NULL) {
148 		return NULL;
149 	}
150 
151 	/* initialize */
152 	convd->from = from;
153 	convd->to = to;
154 
155 	/* create convert filter */
156 	convd->filter1 = NULL;
157 	convd->filter2 = NULL;
158 	if (mbfl_convert_filter_get_vtbl(convd->from->no_encoding, convd->to->no_encoding) != NULL) {
159 		convd->filter1 = mbfl_convert_filter_new(convd->from->no_encoding, convd->to->no_encoding, mbfl_memory_device_output, NULL, &convd->device);
160 	} else {
161 		convd->filter2 = mbfl_convert_filter_new(mbfl_no_encoding_wchar, convd->to->no_encoding, mbfl_memory_device_output, NULL, &convd->device);
162 		if (convd->filter2 != NULL) {
163 			convd->filter1 = mbfl_convert_filter_new(convd->from->no_encoding,
164 					mbfl_no_encoding_wchar,
165 					(int (*)(int, void*))convd->filter2->filter_function,
166 					(int (*)(void*))convd->filter2->filter_flush,
167 					convd->filter2);
168 			if (convd->filter1 == NULL) {
169 				mbfl_convert_filter_delete(convd->filter2);
170 			}
171 		}
172 	}
173 	if (convd->filter1 == NULL) {
174 		return NULL;
175 	}
176 
177 	mbfl_memory_device_init(&convd->device, buf_initsz, buf_initsz/4);
178 
179 	return convd;
180 }
181 
182 
183 void
mbfl_buffer_converter_delete(mbfl_buffer_converter * convd)184 mbfl_buffer_converter_delete(mbfl_buffer_converter *convd)
185 {
186 	if (convd != NULL) {
187 		if (convd->filter1) {
188 			mbfl_convert_filter_delete(convd->filter1);
189 		}
190 		if (convd->filter2) {
191 			mbfl_convert_filter_delete(convd->filter2);
192 		}
193 		mbfl_memory_device_clear(&convd->device);
194 		mbfl_free((void*)convd);
195 	}
196 }
197 
198 void
mbfl_buffer_converter_reset(mbfl_buffer_converter * convd)199 mbfl_buffer_converter_reset(mbfl_buffer_converter *convd)
200 {
201 	mbfl_memory_device_reset(&convd->device);
202 }
203 
204 int
mbfl_buffer_converter_illegal_mode(mbfl_buffer_converter * convd,int mode)205 mbfl_buffer_converter_illegal_mode(mbfl_buffer_converter *convd, int mode)
206 {
207 	if (convd != NULL) {
208 		if (convd->filter2 != NULL) {
209 			convd->filter2->illegal_mode = mode;
210 		} else if (convd->filter1 != NULL) {
211 			convd->filter1->illegal_mode = mode;
212 		} else {
213 			return 0;
214 		}
215 	}
216 
217 	return 1;
218 }
219 
220 int
mbfl_buffer_converter_illegal_substchar(mbfl_buffer_converter * convd,int substchar)221 mbfl_buffer_converter_illegal_substchar(mbfl_buffer_converter *convd, int substchar)
222 {
223 	if (convd != NULL) {
224 		if (convd->filter2 != NULL) {
225 			convd->filter2->illegal_substchar = substchar;
226 		} else if (convd->filter1 != NULL) {
227 			convd->filter1->illegal_substchar = substchar;
228 		} else {
229 			return 0;
230 		}
231 	}
232 
233 	return 1;
234 }
235 
236 int
mbfl_buffer_converter_strncat(mbfl_buffer_converter * convd,const unsigned char * p,int n)237 mbfl_buffer_converter_strncat(mbfl_buffer_converter *convd, const unsigned char *p, int n)
238 {
239 	mbfl_convert_filter *filter;
240 	int (*filter_function)(int c, mbfl_convert_filter *filter);
241 
242 	if (convd != NULL && p != NULL) {
243 		filter = convd->filter1;
244 		if (filter != NULL) {
245 			filter_function = filter->filter_function;
246 			while (n > 0) {
247 				if ((*filter_function)(*p++, filter) < 0) {
248 					break;
249 				}
250 				n--;
251 			}
252 		}
253 	}
254 
255 	return n;
256 }
257 
258 int
mbfl_buffer_converter_feed(mbfl_buffer_converter * convd,mbfl_string * string)259 mbfl_buffer_converter_feed(mbfl_buffer_converter *convd, mbfl_string *string)
260 {
261 	return mbfl_buffer_converter_feed2(convd, string, NULL);
262 }
263 
264 int
mbfl_buffer_converter_feed2(mbfl_buffer_converter * convd,mbfl_string * string,int * loc)265 mbfl_buffer_converter_feed2(mbfl_buffer_converter *convd, mbfl_string *string, int *loc)
266 {
267 	int n;
268 	unsigned char *p;
269 	mbfl_convert_filter *filter;
270 	int (*filter_function)(int c, mbfl_convert_filter *filter);
271 
272 	if (convd == NULL || string == NULL) {
273 		return -1;
274 	}
275 	mbfl_memory_device_realloc(&convd->device, convd->device.pos + string->len, string->len/4);
276 	/* feed data */
277 	n = string->len;
278 	p = string->val;
279 
280 	filter = convd->filter1;
281 	if (filter != NULL) {
282 		filter_function = filter->filter_function;
283 		while (n > 0) {
284 			if ((*filter_function)(*p++, filter) < 0) {
285 				if (loc) {
286 					*loc = p - string->val;
287 				}
288 				return -1;
289 			}
290 			n--;
291 		}
292 	}
293 	if (loc) {
294 		*loc = p - string->val;
295 	}
296 	return 0;
297 }
298 
299 
300 int
mbfl_buffer_converter_flush(mbfl_buffer_converter * convd)301 mbfl_buffer_converter_flush(mbfl_buffer_converter *convd)
302 {
303 	if (convd == NULL) {
304 		return -1;
305 	}
306 
307 	if (convd->filter1 != NULL) {
308 		mbfl_convert_filter_flush(convd->filter1);
309 	}
310 	if (convd->filter2 != NULL) {
311 		mbfl_convert_filter_flush(convd->filter2);
312 	}
313 
314 	return 0;
315 }
316 
317 mbfl_string *
mbfl_buffer_converter_getbuffer(mbfl_buffer_converter * convd,mbfl_string * result)318 mbfl_buffer_converter_getbuffer(mbfl_buffer_converter *convd, mbfl_string *result)
319 {
320 	if (convd != NULL && result != NULL && convd->device.buffer != NULL) {
321 		result->no_encoding = convd->to->no_encoding;
322 		result->val = convd->device.buffer;
323 		result->len = convd->device.pos;
324 	} else {
325 		result = NULL;
326 	}
327 
328 	return result;
329 }
330 
331 mbfl_string *
mbfl_buffer_converter_result(mbfl_buffer_converter * convd,mbfl_string * result)332 mbfl_buffer_converter_result(mbfl_buffer_converter *convd, mbfl_string *result)
333 {
334 	if (convd == NULL || result == NULL) {
335 		return NULL;
336 	}
337 	result->no_encoding = convd->to->no_encoding;
338 	return mbfl_memory_device_result(&convd->device, result);
339 }
340 
341 mbfl_string *
mbfl_buffer_converter_feed_result(mbfl_buffer_converter * convd,mbfl_string * string,mbfl_string * result)342 mbfl_buffer_converter_feed_result(mbfl_buffer_converter *convd, mbfl_string *string,
343 				  mbfl_string *result)
344 {
345 	if (convd == NULL || string == NULL || result == NULL) {
346 		return NULL;
347 	}
348 	mbfl_buffer_converter_feed(convd, string);
349 	if (convd->filter1 != NULL) {
350 		mbfl_convert_filter_flush(convd->filter1);
351 	}
352 	if (convd->filter2 != NULL) {
353 		mbfl_convert_filter_flush(convd->filter2);
354 	}
355 	result->no_encoding = convd->to->no_encoding;
356 	return mbfl_memory_device_result(&convd->device, result);
357 }
358 
mbfl_buffer_illegalchars(mbfl_buffer_converter * convd)359 int mbfl_buffer_illegalchars(mbfl_buffer_converter *convd)
360 {
361 	int num_illegalchars = 0;
362 
363 	if (convd == NULL) {
364 		return 0;
365 	}
366 
367 	if (convd->filter1 != NULL) {
368 		num_illegalchars += convd->filter1->num_illegalchar;
369 	}
370 
371 	if (convd->filter2 != NULL) {
372 		num_illegalchars += convd->filter2->num_illegalchar;
373 	}
374 
375 	return (num_illegalchars);
376 }
377 
378 /*
379  * encoding detector
380  */
381 mbfl_encoding_detector *
mbfl_encoding_detector_new(enum mbfl_no_encoding * elist,int elistsz,int strict)382 mbfl_encoding_detector_new(enum mbfl_no_encoding *elist, int elistsz, int strict)
383 {
384 	mbfl_encoding_detector *identd;
385 
386 	int i, num;
387 	mbfl_identify_filter *filter;
388 
389 	if (elist == NULL || elistsz <= 0) {
390 		return NULL;
391 	}
392 
393 	/* allocate */
394 	identd = (mbfl_encoding_detector*)mbfl_malloc(sizeof(mbfl_encoding_detector));
395 	if (identd == NULL) {
396 		return NULL;
397 	}
398 	identd->filter_list = (mbfl_identify_filter **)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter *));
399 	if (identd->filter_list == NULL) {
400 		mbfl_free(identd);
401 		return NULL;
402 	}
403 
404 	/* create filters */
405 	i = 0;
406 	num = 0;
407 	while (i < elistsz) {
408 		filter = mbfl_identify_filter_new(elist[i]);
409 		if (filter != NULL) {
410 			identd->filter_list[num] = filter;
411 			num++;
412 		}
413 		i++;
414 	}
415 	identd->filter_list_size = num;
416 
417 	/* set strict flag */
418 	identd->strict = strict;
419 
420 	return identd;
421 }
422 
423 mbfl_encoding_detector *
mbfl_encoding_detector_new2(const mbfl_encoding ** elist,int elistsz,int strict)424 mbfl_encoding_detector_new2(const mbfl_encoding **elist, int elistsz, int strict)
425 {
426 	mbfl_encoding_detector *identd;
427 
428 	int i, num;
429 	mbfl_identify_filter *filter;
430 
431 	if (elist == NULL || elistsz <= 0) {
432 		return NULL;
433 	}
434 
435 	/* allocate */
436 	identd = (mbfl_encoding_detector*)mbfl_malloc(sizeof(mbfl_encoding_detector));
437 	if (identd == NULL) {
438 		return NULL;
439 	}
440 	identd->filter_list = (mbfl_identify_filter **)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter *));
441 	if (identd->filter_list == NULL) {
442 		mbfl_free(identd);
443 		return NULL;
444 	}
445 
446 	/* create filters */
447 	i = 0;
448 	num = 0;
449 	while (i < elistsz) {
450 		filter = mbfl_identify_filter_new2(elist[i]);
451 		if (filter != NULL) {
452 			identd->filter_list[num] = filter;
453 			num++;
454 		}
455 		i++;
456 	}
457 	identd->filter_list_size = num;
458 
459 	/* set strict flag */
460 	identd->strict = strict;
461 
462 	return identd;
463 }
464 
465 
466 void
mbfl_encoding_detector_delete(mbfl_encoding_detector * identd)467 mbfl_encoding_detector_delete(mbfl_encoding_detector *identd)
468 {
469 	int i;
470 
471 	if (identd != NULL) {
472 		if (identd->filter_list != NULL) {
473 			i = identd->filter_list_size;
474 			while (i > 0) {
475 				i--;
476 				mbfl_identify_filter_delete(identd->filter_list[i]);
477 			}
478 			mbfl_free((void *)identd->filter_list);
479 		}
480 		mbfl_free((void *)identd);
481 	}
482 }
483 
484 int
mbfl_encoding_detector_feed(mbfl_encoding_detector * identd,mbfl_string * string)485 mbfl_encoding_detector_feed(mbfl_encoding_detector *identd, mbfl_string *string)
486 {
487 	int i, n, num, bad, res;
488 	unsigned char *p;
489 	mbfl_identify_filter *filter;
490 
491 	res = 0;
492 	/* feed data */
493 	if (identd != NULL && string != NULL && string->val != NULL) {
494 		num = identd->filter_list_size;
495 		n = string->len;
496 		p = string->val;
497 		bad = 0;
498 		while (n > 0) {
499 			for (i = 0; i < num; i++) {
500 				filter = identd->filter_list[i];
501 				if (!filter->flag) {
502 					(*filter->filter_function)(*p, filter);
503 					if (filter->flag) {
504 						bad++;
505 					}
506 				}
507 			}
508 			if ((num - 1) <= bad) {
509 				res = 1;
510 				break;
511 			}
512 			p++;
513 			n--;
514 		}
515 	}
516 
517 	return res;
518 }
519 
mbfl_encoding_detector_judge2(mbfl_encoding_detector * identd)520 const mbfl_encoding *mbfl_encoding_detector_judge2(mbfl_encoding_detector *identd)
521 {
522 	mbfl_identify_filter *filter;
523 	const mbfl_encoding *encoding = NULL;
524 	int n;
525 
526 	/* judge */
527 	if (identd != NULL) {
528 		n = identd->filter_list_size - 1;
529 		while (n >= 0) {
530 			filter = identd->filter_list[n];
531 			if (!filter->flag) {
532 				if (!identd->strict || !filter->status) {
533 					encoding = filter->encoding;
534 				}
535 			}
536 			n--;
537 		}
538 
539 		/* fallback judge */
540 		if (!encoding) {
541 			n = identd->filter_list_size - 1;
542 			while (n >= 0) {
543 				filter = identd->filter_list[n];
544 				if (!filter->flag) {
545 					encoding = filter->encoding;
546 				}
547 				n--;
548  			}
549 		}
550 	}
551 
552 	return encoding;
553 }
554 
mbfl_encoding_detector_judge(mbfl_encoding_detector * identd)555 enum mbfl_no_encoding mbfl_encoding_detector_judge(mbfl_encoding_detector *identd)
556 {
557 	const mbfl_encoding *encoding = mbfl_encoding_detector_judge2(identd);
558 	return !encoding ? mbfl_no_encoding_invalid: encoding->no_encoding;
559 }
560 
561 
562 /*
563  * encoding converter
564  */
565 mbfl_string *
mbfl_convert_encoding(mbfl_string * string,mbfl_string * result,enum mbfl_no_encoding toenc)566 mbfl_convert_encoding(
567     mbfl_string *string,
568     mbfl_string *result,
569     enum mbfl_no_encoding toenc)
570 {
571 	int n;
572 	unsigned char *p;
573 	const mbfl_encoding *encoding;
574 	mbfl_memory_device device;
575 	mbfl_convert_filter *filter1;
576 	mbfl_convert_filter *filter2;
577 
578 	/* initialize */
579 	encoding = mbfl_no2encoding(toenc);
580 	if (encoding == NULL || string == NULL || result == NULL) {
581 		return NULL;
582 	}
583 
584 	filter1 = NULL;
585 	filter2 = NULL;
586 	if (mbfl_convert_filter_get_vtbl(string->no_encoding, toenc) != NULL) {
587 		filter1 = mbfl_convert_filter_new(string->no_encoding, toenc, mbfl_memory_device_output, 0, &device);
588 	} else {
589 		filter2 = mbfl_convert_filter_new(mbfl_no_encoding_wchar, toenc, mbfl_memory_device_output, 0, &device);
590 		if (filter2 != NULL) {
591 			filter1 = mbfl_convert_filter_new(string->no_encoding, mbfl_no_encoding_wchar, (int (*)(int, void*))filter2->filter_function, NULL, filter2);
592 			if (filter1 == NULL) {
593 				mbfl_convert_filter_delete(filter2);
594 			}
595 		}
596 	}
597 	if (filter1 == NULL) {
598 		return NULL;
599 	}
600 
601 	if (filter2 != NULL) {
602 		filter2->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
603 		filter2->illegal_substchar = 0x3f;		/* '?' */
604 	}
605 
606 	mbfl_memory_device_init(&device, string->len, (string->len >> 2) + 8);
607 
608 	/* feed data */
609 	n = string->len;
610 	p = string->val;
611 	if (p != NULL) {
612 		while (n > 0) {
613 			if ((*filter1->filter_function)(*p++, filter1) < 0) {
614 				break;
615 			}
616 			n--;
617 		}
618 	}
619 
620 	mbfl_convert_filter_flush(filter1);
621 	mbfl_convert_filter_delete(filter1);
622 	if (filter2 != NULL) {
623 		mbfl_convert_filter_flush(filter2);
624 		mbfl_convert_filter_delete(filter2);
625 	}
626 
627 	return mbfl_memory_device_result(&device, result);
628 }
629 
630 
631 /*
632  * identify encoding
633  */
634 const mbfl_encoding *
mbfl_identify_encoding(mbfl_string * string,enum mbfl_no_encoding * elist,int elistsz,int strict)635 mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict)
636 {
637 	int i, n, num, bad;
638 	unsigned char *p;
639 	mbfl_identify_filter *flist, *filter;
640 	const mbfl_encoding *encoding;
641 
642 	/* flist is an array of mbfl_identify_filter instances */
643 	flist = (mbfl_identify_filter *)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter));
644 	if (flist == NULL) {
645 		return NULL;
646 	}
647 
648 	num = 0;
649 	if (elist != NULL) {
650 		for (i = 0; i < elistsz; i++) {
651 			if (!mbfl_identify_filter_init(&flist[num], elist[i])) {
652 				num++;
653 			}
654 		}
655 	}
656 
657 	/* feed data */
658 	n = string->len;
659 	p = string->val;
660 
661 	if (p != NULL) {
662 		bad = 0;
663 		while (n > 0) {
664 			for (i = 0; i < num; i++) {
665 				filter = &flist[i];
666 				if (!filter->flag) {
667 					(*filter->filter_function)(*p, filter);
668 					if (filter->flag) {
669 						bad++;
670 					}
671 				}
672 			}
673 			if ((num - 1) <= bad && !strict) {
674 				break;
675 			}
676 			p++;
677 			n--;
678 		}
679 	}
680 
681 	/* judge */
682 	encoding = NULL;
683 
684 	for (i = 0; i < num; i++) {
685 		filter = &flist[i];
686 		if (!filter->flag) {
687 			if (strict && filter->status) {
688  				continue;
689  			}
690 			encoding = filter->encoding;
691 			break;
692 		}
693 	}
694 
695 	/* fall-back judge */
696 	if (!encoding) {
697 		for (i = 0; i < num; i++) {
698 			filter = &flist[i];
699 			if (!filter->flag && (!strict || !filter->status)) {
700 				encoding = filter->encoding;
701 				break;
702 			}
703 		}
704 	}
705 
706 	/* cleanup */
707 	/* dtors should be called in reverse order */
708 	i = num; while (--i >= 0) {
709 		mbfl_identify_filter_cleanup(&flist[i]);
710 	}
711 
712 	mbfl_free((void *)flist);
713 
714 	return encoding;
715 }
716 
717 const mbfl_encoding *
mbfl_identify_encoding2(mbfl_string * string,const mbfl_encoding ** elist,int elistsz,int strict)718 mbfl_identify_encoding2(mbfl_string *string, const mbfl_encoding **elist, int elistsz, int strict)
719 {
720 	int i, n, num, bad;
721 	unsigned char *p;
722 	mbfl_identify_filter *flist, *filter;
723 	const mbfl_encoding *encoding;
724 
725 	/* flist is an array of mbfl_identify_filter instances */
726 	flist = (mbfl_identify_filter *)mbfl_calloc(elistsz, sizeof(mbfl_identify_filter));
727 	if (flist == NULL) {
728 		return NULL;
729 	}
730 
731 	num = 0;
732 	if (elist != NULL) {
733 		for (i = 0; i < elistsz; i++) {
734 			if (!mbfl_identify_filter_init2(&flist[num], elist[i])) {
735 				num++;
736 			}
737 		}
738 	}
739 
740 	/* feed data */
741 	n = string->len;
742 	p = string->val;
743 
744 	if (p != NULL) {
745 		bad = 0;
746 		while (n > 0) {
747 			for (i = 0; i < num; i++) {
748 				filter = &flist[i];
749 				if (!filter->flag) {
750 					(*filter->filter_function)(*p, filter);
751 					if (filter->flag) {
752 						bad++;
753 					}
754 				}
755 			}
756 			if ((num - 1) <= bad && !strict) {
757 				break;
758 			}
759 			p++;
760 			n--;
761 		}
762 	}
763 
764 	/* judge */
765 	encoding = NULL;
766 
767 	for (i = 0; i < num; i++) {
768 		filter = &flist[i];
769 		if (!filter->flag) {
770 			if (strict && filter->status) {
771  				continue;
772  			}
773 			encoding = filter->encoding;
774 			break;
775 		}
776 	}
777 
778 	/* fall-back judge */
779 	if (!encoding) {
780 		for (i = 0; i < num; i++) {
781 			filter = &flist[i];
782 			if (!filter->flag && (!strict || !filter->status)) {
783 				encoding = filter->encoding;
784 				break;
785 			}
786 		}
787 	}
788 
789 	/* cleanup */
790 	/* dtors should be called in reverse order */
791 	i = num; while (--i >= 0) {
792 		mbfl_identify_filter_cleanup(&flist[i]);
793 	}
794 
795 	mbfl_free((void *)flist);
796 
797 	return encoding;
798 }
799 
800 /*
801  *  strlen
802  */
803 static int
filter_count_output(int c,void * data)804 filter_count_output(int c, void *data)
805 {
806 	(*(int *)data)++;
807 	return c;
808 }
809 
810 int
mbfl_strlen(mbfl_string * string)811 mbfl_strlen(mbfl_string *string)
812 {
813 	int len, n, m, k;
814 	unsigned char *p;
815 	const unsigned char *mbtab;
816 	const mbfl_encoding *encoding;
817 
818 	encoding = mbfl_no2encoding(string->no_encoding);
819 	if (encoding == NULL || string == NULL) {
820 		return -1;
821 	}
822 
823 	len = 0;
824 	if (encoding->flag & MBFL_ENCTYPE_SBCS) {
825 		len = string->len;
826 	} else if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
827 		len = string->len/2;
828 	} else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
829 		len = string->len/4;
830 	} else if (encoding->mblen_table != NULL) {
831 		mbtab = encoding->mblen_table;
832 		n = 0;
833 		p = string->val;
834 		k = string->len;
835 		/* count */
836 		if (p != NULL) {
837 			while (n < k) {
838 				m = mbtab[*p];
839 				n += m;
840 				p += m;
841 				len++;
842 			};
843 		}
844 	} else {
845 		/* wchar filter */
846 		mbfl_convert_filter *filter = mbfl_convert_filter_new(
847 		  string->no_encoding,
848 		  mbfl_no_encoding_wchar,
849 		  filter_count_output, 0, &len);
850 		if (filter == NULL) {
851 			return -1;
852 		}
853 		/* count */
854 		n = string->len;
855 		p = string->val;
856 		if (p != NULL) {
857 			while (n > 0) {
858 				(*filter->filter_function)(*p++, filter);
859 				n--;
860 			}
861 		}
862 		mbfl_convert_filter_delete(filter);
863 	}
864 
865 	return len;
866 }
867 
868 
869 /*
870  *  strpos
871  */
872 struct collector_strpos_data {
873 	mbfl_convert_filter *next_filter;
874 	mbfl_wchar_device needle;
875 	int needle_len;
876 	int start;
877 	int output;
878 	int found_pos;
879 	int needle_pos;
880 	int matched_pos;
881 };
882 
883 static int
collector_strpos(int c,void * data)884 collector_strpos(int c, void* data)
885 {
886 	int *p, *h, *m, n;
887 	struct collector_strpos_data *pc = (struct collector_strpos_data*)data;
888 
889 	if (pc->output >= pc->start) {
890 		if (c == (int)pc->needle.buffer[pc->needle_pos]) {
891 			if (pc->needle_pos == 0) {
892 				pc->found_pos = pc->output;			/* found position */
893 			}
894 			pc->needle_pos++;						/* needle pointer */
895 			if (pc->needle_pos >= pc->needle_len) {
896 				pc->matched_pos = pc->found_pos;	/* matched position */
897 				pc->needle_pos--;
898 				goto retry;
899 			}
900 		} else if (pc->needle_pos != 0) {
901 retry:
902 			h = (int *)pc->needle.buffer;
903 			h++;
904 			for (;;) {
905 				pc->found_pos++;
906 				p = h;
907 				m = (int *)pc->needle.buffer;
908 				n = pc->needle_pos - 1;
909 				while (n > 0 && *p == *m) {
910 					n--;
911 					p++;
912 					m++;
913 				}
914 				if (n <= 0) {
915 					if (*m != c) {
916 						pc->needle_pos = 0;
917 					}
918 					break;
919 				} else {
920 					h++;
921 					pc->needle_pos--;
922 				}
923 			}
924 		}
925 	}
926 
927 	pc->output++;
928 	return c;
929 }
930 
931 /*
932  *	oddlen
933  */
934 int
mbfl_oddlen(mbfl_string * string)935 mbfl_oddlen(mbfl_string *string)
936 {
937 	int len, n, m, k;
938 	unsigned char *p;
939 	const unsigned char *mbtab;
940 	const mbfl_encoding *encoding;
941 
942 
943 	if (string == NULL) {
944 		return -1;
945 	}
946 	encoding = mbfl_no2encoding(string->no_encoding);
947 	if (encoding == NULL) {
948 		return -1;
949 	}
950 
951 	len = 0;
952 	if (encoding->flag & MBFL_ENCTYPE_SBCS) {
953 		return 0;
954 	} else if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
955 		return len % 2;
956 	} else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
957 		return len % 4;
958 	} else if (encoding->mblen_table != NULL) {
959  		mbtab = encoding->mblen_table;
960  		n = 0;
961 		p = string->val;
962 		k = string->len;
963 		/* count */
964 		if (p != NULL) {
965 			while (n < k) {
966 				m = mbtab[*p];
967 				n += m;
968 				p += m;
969 			};
970 		}
971 		return n-k;
972 	} else {
973 		/* how can i do ? */
974 		return 0;
975 	}
976 	/* NOT REACHED */
977 }
978 
979 int
mbfl_strpos(mbfl_string * haystack,mbfl_string * needle,int offset,int reverse)980 mbfl_strpos(
981     mbfl_string *haystack,
982     mbfl_string *needle,
983     int offset,
984     int reverse)
985 {
986 	int result;
987 	mbfl_string _haystack_u8, _needle_u8;
988 	const mbfl_string *haystack_u8, *needle_u8 = NULL;
989 	const unsigned char *u8_tbl;
990 
991 	if (haystack == NULL || haystack->val == NULL || needle == NULL || needle->val == NULL) {
992 		return -8;
993 	}
994 
995 	{
996 		const mbfl_encoding *u8_enc;
997 		u8_enc = mbfl_no2encoding(mbfl_no_encoding_utf8);
998 		if (u8_enc == NULL || u8_enc->mblen_table == NULL) {
999 			return -8;
1000 		}
1001 		u8_tbl = u8_enc->mblen_table;
1002 	}
1003 
1004 	if (haystack->no_encoding != mbfl_no_encoding_utf8) {
1005 		mbfl_string_init(&_haystack_u8);
1006 		haystack_u8 = mbfl_convert_encoding(haystack, &_haystack_u8, mbfl_no_encoding_utf8);
1007 		if (haystack_u8 == NULL) {
1008 			result = -4;
1009 			goto out;
1010 		}
1011 	} else {
1012 		haystack_u8 = haystack;
1013 	}
1014 
1015 	if (needle->no_encoding != mbfl_no_encoding_utf8) {
1016 		mbfl_string_init(&_needle_u8);
1017 		needle_u8 = mbfl_convert_encoding(needle, &_needle_u8, mbfl_no_encoding_utf8);
1018 		if (needle_u8 == NULL) {
1019 			result = -4;
1020 			goto out;
1021 		}
1022 	} else {
1023 		needle_u8 = needle;
1024 	}
1025 
1026 	if (needle_u8->len < 1) {
1027 		result = -8;
1028 		goto out;
1029 	}
1030 
1031 	result = -1;
1032 	if (haystack_u8->len < needle_u8->len) {
1033 		goto out;
1034 	}
1035 
1036 	if (!reverse) {
1037 		unsigned int jtbl[1 << (sizeof(unsigned char) * 8)];
1038 		unsigned int needle_u8_len = needle_u8->len;
1039 		unsigned int i;
1040 		const unsigned char *p, *q, *e;
1041 		const unsigned char *haystack_u8_val = haystack_u8->val,
1042 		                    *needle_u8_val = needle_u8->val;
1043 		for (i = 0; i < sizeof(jtbl) / sizeof(*jtbl); ++i) {
1044 			jtbl[i] = needle_u8_len + 1;
1045 		}
1046 		for (i = 0; i < needle_u8_len - 1; ++i) {
1047 			jtbl[needle_u8_val[i]] = needle_u8_len - i;
1048 		}
1049 		e = haystack_u8_val + haystack_u8->len;
1050 		p = haystack_u8_val;
1051 		while (--offset >= 0) {
1052 			if (p >= e) {
1053 				result = -16;
1054 				goto out;
1055 			}
1056 			p += u8_tbl[*p];
1057 		}
1058 		p += needle_u8_len;
1059 		if (p > e) {
1060 			goto out;
1061 		}
1062 		while (p <= e) {
1063 			const unsigned char *pv = p;
1064 			q = needle_u8_val + needle_u8_len;
1065 			for (;;) {
1066 				if (q == needle_u8_val) {
1067 					result = 0;
1068 					while (p > haystack_u8_val) {
1069 						unsigned char c = *--p;
1070 						if (c < 0x80) {
1071 							++result;
1072 						} else if ((c & 0xc0) != 0x80) {
1073 							++result;
1074 						}
1075 					}
1076 					goto out;
1077 				}
1078 				if (*--q != *--p) {
1079 					break;
1080 				}
1081 			}
1082 			p += jtbl[*p];
1083 			if (p <= pv) {
1084 				p = pv + 1;
1085 			}
1086 		}
1087 	} else {
1088 		unsigned int jtbl[1 << (sizeof(unsigned char) * 8)];
1089 		unsigned int needle_u8_len = needle_u8->len, needle_len = 0;
1090 		unsigned int i;
1091 		const unsigned char *p, *e, *q, *qe;
1092 		const unsigned char *haystack_u8_val = haystack_u8->val,
1093 		                    *needle_u8_val = needle_u8->val;
1094 		for (i = 0; i < sizeof(jtbl) / sizeof(*jtbl); ++i) {
1095 			jtbl[i] = needle_u8_len;
1096 		}
1097 		for (i = needle_u8_len - 1; i > 0; --i) {
1098 			unsigned char c = needle_u8_val[i];
1099 			jtbl[c] = i;
1100 			if (c < 0x80) {
1101 				++needle_len;
1102 			} else if ((c & 0xc0) != 0x80) {
1103 				++needle_len;
1104 			}
1105 		}
1106 		{
1107 			unsigned char c = needle_u8_val[0];
1108 			if (c < 0x80) {
1109 				++needle_len;
1110 			} else if ((c & 0xc0) != 0x80) {
1111 				++needle_len;
1112 			}
1113 		}
1114 		e = haystack_u8_val;
1115 		p = e + haystack_u8->len;
1116 		qe = needle_u8_val + needle_u8_len;
1117 		if (offset < 0) {
1118 			if (-offset > needle_len) {
1119 				offset += needle_len;
1120 				while (offset < 0) {
1121 					unsigned char c;
1122 					if (p <= e) {
1123 						result = -16;
1124 						goto out;
1125 					}
1126 					c = *(--p);
1127 					if (c < 0x80) {
1128 						++offset;
1129 					} else if ((c & 0xc0) != 0x80) {
1130 						++offset;
1131 					}
1132 				}
1133 			}
1134 		} else {
1135 			const unsigned char *ee = haystack_u8_val + haystack_u8->len;
1136 			while (--offset >= 0) {
1137 				if (e >= ee) {
1138 					result = -16;
1139 					goto out;
1140 				}
1141 				e += u8_tbl[*e];
1142 			}
1143 		}
1144 		if (p < e + needle_u8_len) {
1145 			goto out;
1146 		}
1147 		p -= needle_u8_len;
1148 		while (p >= e) {
1149 			const unsigned char *pv = p;
1150 			q = needle_u8_val;
1151 			for (;;) {
1152 				if (q == qe) {
1153 					result = 0;
1154 					p -= needle_u8_len;
1155 					while (p > haystack_u8_val) {
1156 						unsigned char c = *--p;
1157 						if (c < 0x80) {
1158 							++result;
1159 						} else if ((c & 0xc0) != 0x80) {
1160 							++result;
1161 						}
1162 					}
1163 					goto out;
1164 				}
1165 				if (*q != *p) {
1166 					break;
1167 				}
1168 				++p, ++q;
1169 			}
1170 			p -= jtbl[*p];
1171 			if (p >= pv) {
1172 				p = pv - 1;
1173 			}
1174 		}
1175 	}
1176 out:
1177 	if (haystack_u8 == &_haystack_u8) {
1178 		mbfl_string_clear(&_haystack_u8);
1179 	}
1180 	if (needle_u8 == &_needle_u8) {
1181 		mbfl_string_clear(&_needle_u8);
1182 	}
1183 	return result;
1184 }
1185 
1186 /*
1187  *  substr_count
1188  */
1189 
1190 int
mbfl_substr_count(mbfl_string * haystack,mbfl_string * needle)1191 mbfl_substr_count(
1192     mbfl_string *haystack,
1193     mbfl_string *needle
1194    )
1195 {
1196 	int n, result = 0;
1197 	unsigned char *p;
1198 	mbfl_convert_filter *filter;
1199 	struct collector_strpos_data pc;
1200 
1201 	if (haystack == NULL || needle == NULL) {
1202 		return -8;
1203 	}
1204 	/* needle is converted into wchar */
1205 	mbfl_wchar_device_init(&pc.needle);
1206 	filter = mbfl_convert_filter_new(
1207 	  needle->no_encoding,
1208 	  mbfl_no_encoding_wchar,
1209 	  mbfl_wchar_device_output, 0, &pc.needle);
1210 	if (filter == NULL) {
1211 		return -4;
1212 	}
1213 	p = needle->val;
1214 	n = needle->len;
1215 	if (p != NULL) {
1216 		while (n > 0) {
1217 			if ((*filter->filter_function)(*p++, filter) < 0) {
1218 				break;
1219 			}
1220 			n--;
1221 		}
1222 	}
1223 	mbfl_convert_filter_flush(filter);
1224 	mbfl_convert_filter_delete(filter);
1225 	pc.needle_len = pc.needle.pos;
1226 	if (pc.needle.buffer == NULL) {
1227 		return -4;
1228 	}
1229 	if (pc.needle_len <= 0) {
1230 		mbfl_wchar_device_clear(&pc.needle);
1231 		return -2;
1232 	}
1233 	/* initialize filter and collector data */
1234 	filter = mbfl_convert_filter_new(
1235 	  haystack->no_encoding,
1236 	  mbfl_no_encoding_wchar,
1237 	  collector_strpos, 0, &pc);
1238 	if (filter == NULL) {
1239 		mbfl_wchar_device_clear(&pc.needle);
1240 		return -4;
1241 	}
1242 	pc.start = 0;
1243 	pc.output = 0;
1244 	pc.needle_pos = 0;
1245 	pc.found_pos = 0;
1246 	pc.matched_pos = -1;
1247 
1248 	/* feed data */
1249 	p = haystack->val;
1250 	n = haystack->len;
1251 	if (p != NULL) {
1252 		while (n > 0) {
1253 			if ((*filter->filter_function)(*p++, filter) < 0) {
1254 				pc.matched_pos = -4;
1255 				break;
1256 			}
1257 			if (pc.matched_pos >= 0) {
1258 				++result;
1259 				pc.matched_pos = -1;
1260 				pc.needle_pos = 0;
1261 			}
1262 			n--;
1263 		}
1264 	}
1265 	mbfl_convert_filter_flush(filter);
1266 	mbfl_convert_filter_delete(filter);
1267 	mbfl_wchar_device_clear(&pc.needle);
1268 
1269 	return result;
1270 }
1271 
1272 /*
1273  *  substr
1274  */
1275 struct collector_substr_data {
1276 	mbfl_convert_filter *next_filter;
1277 	int start;
1278 	int stop;
1279 	int output;
1280 };
1281 
1282 static int
collector_substr(int c,void * data)1283 collector_substr(int c, void* data)
1284 {
1285 	struct collector_substr_data *pc = (struct collector_substr_data*)data;
1286 
1287 	if (pc->output >= pc->stop) {
1288 		return -1;
1289 	}
1290 
1291 	if (pc->output >= pc->start) {
1292 		(*pc->next_filter->filter_function)(c, pc->next_filter);
1293 	}
1294 
1295 	pc->output++;
1296 
1297 	return c;
1298 }
1299 
1300 mbfl_string *
mbfl_substr(mbfl_string * string,mbfl_string * result,int from,int length)1301 mbfl_substr(
1302     mbfl_string *string,
1303     mbfl_string *result,
1304     int from,
1305     int length)
1306 {
1307 	const mbfl_encoding *encoding;
1308 	int n, m, k, len, start, end;
1309 	unsigned char *p, *w;
1310 	const unsigned char *mbtab;
1311 
1312 	encoding = mbfl_no2encoding(string->no_encoding);
1313 	if (encoding == NULL || string == NULL || result == NULL) {
1314 		return NULL;
1315 	}
1316 	mbfl_string_init(result);
1317 	result->no_language = string->no_language;
1318 	result->no_encoding = string->no_encoding;
1319 
1320 	if ((encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE | MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) ||
1321 	   encoding->mblen_table != NULL) {
1322 		len = string->len;
1323 		start = from;
1324 		end = from + length;
1325 		if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
1326 			start *= 2;
1327 			end = start + length*2;
1328 		} else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
1329 			start *= 4;
1330 			end = start + length*4;
1331 		} else if (encoding->mblen_table != NULL) {
1332 			mbtab = encoding->mblen_table;
1333 			start = 0;
1334 			end = 0;
1335 			n = 0;
1336 			k = 0;
1337 			p = string->val;
1338 			if (p != NULL) {
1339 				/* search start position */
1340 				while (k <= from) {
1341 					start = n;
1342 					if (n >= len) {
1343 						break;
1344 					}
1345 					m = mbtab[*p];
1346 					n += m;
1347 					p += m;
1348 					k++;
1349 				}
1350 				/* detect end position */
1351 				k = 0;
1352 				end = start;
1353 				while (k < length) {
1354 					end = n;
1355 					if (n >= len) {
1356 						break;
1357 					}
1358 					m = mbtab[*p];
1359 					n += m;
1360 					p += m;
1361 					k++;
1362 				}
1363 			}
1364 		}
1365 
1366 		if (start > len) {
1367 			start = len;
1368 		}
1369 		if (start < 0) {
1370 			start = 0;
1371 		}
1372 		if (end > len) {
1373 			end = len;
1374 		}
1375 		if (end < 0) {
1376 			end = 0;
1377 		}
1378 		if (start > end) {
1379 			start = end;
1380 		}
1381 
1382 		/* allocate memory and copy */
1383 		n = end - start;
1384 		result->len = 0;
1385 		result->val = w = (unsigned char*)mbfl_malloc((n + 8)*sizeof(unsigned char));
1386 		if (w != NULL) {
1387 			p = string->val;
1388 			if (p != NULL) {
1389 				p += start;
1390 				result->len = n;
1391 				while (n > 0) {
1392 					*w++ = *p++;
1393 					n--;
1394 				}
1395 			}
1396 			*w++ = '\0';
1397 			*w++ = '\0';
1398 			*w++ = '\0';
1399 			*w = '\0';
1400 		} else {
1401 			result = NULL;
1402 		}
1403 	} else {
1404 		mbfl_memory_device device;
1405 		struct collector_substr_data pc;
1406 		mbfl_convert_filter *decoder;
1407 		mbfl_convert_filter *encoder;
1408 
1409 		mbfl_memory_device_init(&device, length + 1, 0);
1410 		mbfl_string_init(result);
1411 		result->no_language = string->no_language;
1412 		result->no_encoding = string->no_encoding;
1413 		/* output code filter */
1414 		decoder = mbfl_convert_filter_new(
1415 		    mbfl_no_encoding_wchar,
1416 		    string->no_encoding,
1417 		    mbfl_memory_device_output, 0, &device);
1418 		/* wchar filter */
1419 		encoder = mbfl_convert_filter_new(
1420 		    string->no_encoding,
1421 		    mbfl_no_encoding_wchar,
1422 		    collector_substr, 0, &pc);
1423 		if (decoder == NULL || encoder == NULL) {
1424 			mbfl_convert_filter_delete(encoder);
1425 			mbfl_convert_filter_delete(decoder);
1426 			return NULL;
1427 		}
1428 		pc.next_filter = decoder;
1429 		pc.start = from;
1430 		pc.stop = from + length;
1431 		pc.output = 0;
1432 
1433 		/* feed data */
1434 		p = string->val;
1435 		n = string->len;
1436 		if (p != NULL) {
1437 			while (n > 0) {
1438 				if ((*encoder->filter_function)(*p++, encoder) < 0) {
1439 					break;
1440 				}
1441 				n--;
1442 			}
1443 		}
1444 
1445 		mbfl_convert_filter_flush(encoder);
1446 		mbfl_convert_filter_flush(decoder);
1447 		result = mbfl_memory_device_result(&device, result);
1448 		mbfl_convert_filter_delete(encoder);
1449 		mbfl_convert_filter_delete(decoder);
1450 	}
1451 
1452 	return result;
1453 }
1454 
1455 /*
1456  *  strcut
1457  */
1458 mbfl_string *
mbfl_strcut(mbfl_string * string,mbfl_string * result,int from,int length)1459 mbfl_strcut(
1460     mbfl_string *string,
1461     mbfl_string *result,
1462     int from,
1463     int length)
1464 {
1465 	const mbfl_encoding *encoding;
1466 	mbfl_memory_device device;
1467 
1468 	/* validate the parameters */
1469 	if (string == NULL || string->val == NULL || result == NULL) {
1470 		return NULL;
1471 	}
1472 
1473 	if (from < 0 || length < 0) {
1474 		return NULL;
1475 	}
1476 
1477 	if (from >= string->len) {
1478 		from = string->len;
1479 	}
1480 
1481 	encoding = mbfl_no2encoding(string->no_encoding);
1482 	if (encoding == NULL) {
1483 		return NULL;
1484 	}
1485 
1486 	mbfl_string_init(result);
1487 	result->no_language = string->no_language;
1488 	result->no_encoding = string->no_encoding;
1489 
1490 	if ((encoding->flag & (MBFL_ENCTYPE_SBCS
1491 				| MBFL_ENCTYPE_WCS2BE
1492 				| MBFL_ENCTYPE_WCS2LE
1493 				| MBFL_ENCTYPE_WCS4BE
1494 				| MBFL_ENCTYPE_WCS4LE))
1495 			|| encoding->mblen_table != NULL) {
1496 		const unsigned char *start = NULL;
1497 		const unsigned char *end = NULL;
1498 		unsigned char *w;
1499 		unsigned int sz;
1500 
1501 		if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
1502 			from &= -2;
1503 
1504 			if (length >= string->len - from) {
1505 				length = string->len - from;
1506 			}
1507 
1508 			start = string->val + from;
1509 			end   = start + (length & -2);
1510 		} else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
1511 			from &= -4;
1512 
1513 			if (length >= string->len - from) {
1514 				length = string->len - from;
1515 			}
1516 
1517 			start = string->val + from;
1518 			end   = start + (length & -4);
1519 		} else if ((encoding->flag & MBFL_ENCTYPE_SBCS)) {
1520 			if (length >= string->len - from) {
1521 				length = string->len - from;
1522 			}
1523 
1524 			start = string->val + from;
1525 			end = start + length;
1526 		} else if (encoding->mblen_table != NULL) {
1527 			const unsigned char *mbtab = encoding->mblen_table;
1528 			const unsigned char *p, *q;
1529 			int m;
1530 
1531 			/* search start position */
1532 			for (m = 0, p = string->val, q = p + from;
1533 					p < q; p += (m = mbtab[*p]));
1534 
1535 			if (p > q) {
1536 				p -= m;
1537 			}
1538 
1539 			start = p;
1540 
1541 			/* search end position */
1542 			if (length >= (int)string->len - (start - string->val)) {
1543 				end = string->val + string->len;
1544 			} else {
1545 				for (q = p + length; p < q; p += (m = mbtab[*p]));
1546 
1547 				if (p > q) {
1548 					p -= m;
1549 				}
1550 				end = p;
1551 			}
1552 		} else {
1553 			/* never reached */
1554 			return NULL;
1555 		}
1556 
1557 		/* allocate memory and copy string */
1558 		sz = end - start;
1559 		if ((w = (unsigned char*)mbfl_calloc(sz + 8,
1560 				sizeof(unsigned char))) == NULL) {
1561 			return NULL;
1562 		}
1563 
1564 		memcpy(w, start, sz);
1565 		w[sz] = '\0';
1566 		w[sz + 1] = '\0';
1567 		w[sz + 2] = '\0';
1568 		w[sz + 3] = '\0';
1569 
1570 		result->val = w;
1571 		result->len = sz;
1572 	} else {
1573 		mbfl_convert_filter *encoder     = NULL;
1574 		mbfl_convert_filter *decoder     = NULL;
1575 		const unsigned char *p, *q, *r;
1576 		struct {
1577 			mbfl_convert_filter encoder;
1578 			mbfl_convert_filter decoder;
1579 			const unsigned char *p;
1580 			int pos;
1581 		} bk, _bk;
1582 
1583 		/* output code filter */
1584 		if (!(decoder = mbfl_convert_filter_new(
1585 				mbfl_no_encoding_wchar,
1586 				string->no_encoding,
1587 				mbfl_memory_device_output, 0, &device))) {
1588 			return NULL;
1589 		}
1590 
1591 		/* wchar filter */
1592 		if (!(encoder = mbfl_convert_filter_new(
1593 				string->no_encoding,
1594 				mbfl_no_encoding_wchar,
1595 				mbfl_filter_output_null,
1596 				NULL, NULL))) {
1597 			mbfl_convert_filter_delete(decoder);
1598 			return NULL;
1599 		}
1600 
1601 		mbfl_memory_device_init(&device, length + 8, 0);
1602 
1603 		p = string->val;
1604 
1605 		/* search start position */
1606 		for (q = string->val + from; p < q; p++) {
1607 			(*encoder->filter_function)(*p, encoder);
1608 		}
1609 
1610 		/* switch the drain direction */
1611 		encoder->output_function = (int(*)(int,void *))decoder->filter_function;
1612 		encoder->flush_function = (int(*)(void *))decoder->filter_flush;
1613 		encoder->data = decoder;
1614 
1615 		q = string->val + string->len;
1616 
1617 		/* save the encoder, decoder state and the pointer */
1618 		mbfl_convert_filter_copy(decoder, &_bk.decoder);
1619 		mbfl_convert_filter_copy(encoder, &_bk.encoder);
1620 		_bk.p = p;
1621 		_bk.pos = device.pos;
1622 
1623 		if (length > q - p) {
1624 			length = q - p;
1625 		}
1626 
1627 		if (length >= 20) {
1628 			/* output a little shorter than "length" */
1629 			/* XXX: the constant "20" was determined purely on the heuristics. */
1630 			for (r = p + length - 20; p < r; p++) {
1631 				(*encoder->filter_function)(*p, encoder);
1632 			}
1633 
1634 			/* if the offset of the resulting string exceeds the length,
1635 			 * then restore the state */
1636 			if (device.pos > length) {
1637 				p = _bk.p;
1638 				device.pos = _bk.pos;
1639 				decoder->filter_dtor(decoder);
1640 				encoder->filter_dtor(encoder);
1641 				mbfl_convert_filter_copy(&_bk.decoder, decoder);
1642 				mbfl_convert_filter_copy(&_bk.encoder, encoder);
1643 				bk = _bk;
1644 			} else {
1645 				/* save the encoder, decoder state and the pointer */
1646 				mbfl_convert_filter_copy(decoder, &bk.decoder);
1647 				mbfl_convert_filter_copy(encoder, &bk.encoder);
1648 				bk.p = p;
1649 				bk.pos = device.pos;
1650 
1651 				/* flush the stream */
1652 				(*encoder->filter_flush)(encoder);
1653 
1654 				/* if the offset of the resulting string exceeds the length,
1655 				 * then restore the state */
1656 				if (device.pos > length) {
1657 					bk.decoder.filter_dtor(&bk.decoder);
1658 					bk.encoder.filter_dtor(&bk.encoder);
1659 
1660 					p = _bk.p;
1661 					device.pos = _bk.pos;
1662 					decoder->filter_dtor(decoder);
1663 					encoder->filter_dtor(encoder);
1664 					mbfl_convert_filter_copy(&_bk.decoder, decoder);
1665 					mbfl_convert_filter_copy(&_bk.encoder, encoder);
1666 					bk = _bk;
1667 				} else {
1668 					_bk.decoder.filter_dtor(&_bk.decoder);
1669 					_bk.encoder.filter_dtor(&_bk.encoder);
1670 
1671 					p = bk.p;
1672 					device.pos = bk.pos;
1673 					decoder->filter_dtor(decoder);
1674 					encoder->filter_dtor(encoder);
1675 					mbfl_convert_filter_copy(&bk.decoder, decoder);
1676 					mbfl_convert_filter_copy(&bk.encoder, encoder);
1677 				}
1678 			}
1679 		} else {
1680 			bk = _bk;
1681 		}
1682 
1683 		/* detect end position */
1684 		while (p < q) {
1685 			(*encoder->filter_function)(*p, encoder);
1686 
1687 			if (device.pos > length) {
1688 				/* restore filter */
1689 				p = bk.p;
1690 				device.pos = bk.pos;
1691 				decoder->filter_dtor(decoder);
1692 				encoder->filter_dtor(encoder);
1693 				mbfl_convert_filter_copy(&bk.decoder, decoder);
1694 				mbfl_convert_filter_copy(&bk.encoder, encoder);
1695 				break;
1696 			}
1697 
1698 			p++;
1699 
1700 			/* backup current state */
1701 			mbfl_convert_filter_copy(decoder, &_bk.decoder);
1702 			mbfl_convert_filter_copy(encoder, &_bk.encoder);
1703 			_bk.pos = device.pos;
1704 			_bk.p = p;
1705 
1706 			(*encoder->filter_flush)(encoder);
1707 
1708 			if (device.pos > length) {
1709 				_bk.decoder.filter_dtor(&_bk.decoder);
1710 				_bk.encoder.filter_dtor(&_bk.encoder);
1711 
1712 				/* restore filter */
1713 				p = bk.p;
1714 				device.pos = bk.pos;
1715 				decoder->filter_dtor(decoder);
1716 				encoder->filter_dtor(encoder);
1717 				mbfl_convert_filter_copy(&bk.decoder, decoder);
1718 				mbfl_convert_filter_copy(&bk.encoder, encoder);
1719 				break;
1720 			}
1721 
1722 			bk.decoder.filter_dtor(&bk.decoder);
1723 			bk.encoder.filter_dtor(&bk.encoder);
1724 
1725 			p = _bk.p;
1726 			device.pos = _bk.pos;
1727 			decoder->filter_dtor(decoder);
1728 			encoder->filter_dtor(encoder);
1729 			mbfl_convert_filter_copy(&_bk.decoder, decoder);
1730 			mbfl_convert_filter_copy(&_bk.encoder, encoder);
1731 
1732 			bk = _bk;
1733 		}
1734 
1735 		(*encoder->filter_flush)(encoder);
1736 
1737 		bk.decoder.filter_dtor(&bk.decoder);
1738 		bk.encoder.filter_dtor(&bk.encoder);
1739 
1740 		result = mbfl_memory_device_result(&device, result);
1741 
1742 		mbfl_convert_filter_delete(encoder);
1743 		mbfl_convert_filter_delete(decoder);
1744 	}
1745 
1746 	return result;
1747 }
1748 
1749 
1750 /*
1751  *  strwidth
1752  */
is_fullwidth(int c)1753 static int is_fullwidth(int c)
1754 {
1755 	int i;
1756 
1757 	if (c < mbfl_eaw_table[0].begin) {
1758 		return 0;
1759 	}
1760 
1761 	for (i = 0; i < sizeof(mbfl_eaw_table) / sizeof(mbfl_eaw_table[0]); i++) {
1762 		if (mbfl_eaw_table[i].begin <= c && c <= mbfl_eaw_table[i].end) {
1763 			return 1;
1764 		}
1765 	}
1766 
1767 	return 0;
1768 }
1769 
1770 static int
filter_count_width(int c,void * data)1771 filter_count_width(int c, void* data)
1772 {
1773 	(*(int *)data) += (is_fullwidth(c) ? 2: 1);
1774 	return c;
1775 }
1776 
1777 int
mbfl_strwidth(mbfl_string * string)1778 mbfl_strwidth(mbfl_string *string)
1779 {
1780 	int len, n;
1781 	unsigned char *p;
1782 	mbfl_convert_filter *filter;
1783 
1784 	len = 0;
1785 	if (string->len > 0 && string->val != NULL) {
1786 		/* wchar filter */
1787 		filter = mbfl_convert_filter_new(
1788 		    string->no_encoding,
1789 		    mbfl_no_encoding_wchar,
1790 		    filter_count_width, 0, &len);
1791 		if (filter == NULL) {
1792 			mbfl_convert_filter_delete(filter);
1793 			return -1;
1794 		}
1795 
1796 		/* feed data */
1797 		p = string->val;
1798 		n = string->len;
1799 		while (n > 0) {
1800 			(*filter->filter_function)(*p++, filter);
1801 			n--;
1802 		}
1803 
1804 		mbfl_convert_filter_flush(filter);
1805 		mbfl_convert_filter_delete(filter);
1806 	}
1807 
1808 	return len;
1809 }
1810 
1811 
1812 /*
1813  *  strimwidth
1814  */
1815 struct collector_strimwidth_data {
1816 	mbfl_convert_filter *decoder;
1817 	mbfl_convert_filter *decoder_backup;
1818 	mbfl_memory_device device;
1819 	int from;
1820 	int width;
1821 	int outwidth;
1822 	int outchar;
1823 	int status;
1824 	int endpos;
1825 };
1826 
1827 static int
collector_strimwidth(int c,void * data)1828 collector_strimwidth(int c, void* data)
1829 {
1830 	struct collector_strimwidth_data *pc = (struct collector_strimwidth_data*)data;
1831 
1832 	switch (pc->status) {
1833 	case 10:
1834 		(*pc->decoder->filter_function)(c, pc->decoder);
1835 		break;
1836 	default:
1837 		if (pc->outchar >= pc->from) {
1838 			pc->outwidth += (is_fullwidth(c) ? 2: 1);
1839 
1840 			if (pc->outwidth > pc->width) {
1841 				if (pc->status == 0) {
1842 					pc->endpos = pc->device.pos;
1843 					mbfl_convert_filter_copy(pc->decoder, pc->decoder_backup);
1844 				}
1845 				pc->status++;
1846 				(*pc->decoder->filter_function)(c, pc->decoder);
1847 				c = -1;
1848 			} else {
1849 				(*pc->decoder->filter_function)(c, pc->decoder);
1850 			}
1851 		}
1852 		pc->outchar++;
1853 		break;
1854 	}
1855 
1856 	return c;
1857 }
1858 
1859 mbfl_string *
mbfl_strimwidth(mbfl_string * string,mbfl_string * marker,mbfl_string * result,int from,int width)1860 mbfl_strimwidth(
1861     mbfl_string *string,
1862     mbfl_string *marker,
1863     mbfl_string *result,
1864     int from,
1865     int width)
1866 {
1867 	struct collector_strimwidth_data pc;
1868 	mbfl_convert_filter *encoder;
1869 	int n, mkwidth;
1870 	unsigned char *p;
1871 
1872 	if (string == NULL || result == NULL) {
1873 		return NULL;
1874 	}
1875 	mbfl_string_init(result);
1876 	result->no_language = string->no_language;
1877 	result->no_encoding = string->no_encoding;
1878 	mbfl_memory_device_init(&pc.device, width, 0);
1879 
1880 	/* output code filter */
1881 	pc.decoder = mbfl_convert_filter_new(
1882 	    mbfl_no_encoding_wchar,
1883 	    string->no_encoding,
1884 	    mbfl_memory_device_output, 0, &pc.device);
1885 	pc.decoder_backup = mbfl_convert_filter_new(
1886 	    mbfl_no_encoding_wchar,
1887 	    string->no_encoding,
1888 	    mbfl_memory_device_output, 0, &pc.device);
1889 	/* wchar filter */
1890 	encoder = mbfl_convert_filter_new(
1891 	    string->no_encoding,
1892 	    mbfl_no_encoding_wchar,
1893 	    collector_strimwidth, 0, &pc);
1894 	if (pc.decoder == NULL || pc.decoder_backup == NULL || encoder == NULL) {
1895 		mbfl_convert_filter_delete(encoder);
1896 		mbfl_convert_filter_delete(pc.decoder);
1897 		mbfl_convert_filter_delete(pc.decoder_backup);
1898 		return NULL;
1899 	}
1900 	mkwidth = 0;
1901 	if (marker) {
1902 		mkwidth = mbfl_strwidth(marker);
1903 	}
1904 	pc.from = from;
1905 	pc.width = width - mkwidth;
1906 	pc.outwidth = 0;
1907 	pc.outchar = 0;
1908 	pc.status = 0;
1909 	pc.endpos = 0;
1910 
1911 	/* feed data */
1912 	p = string->val;
1913 	n = string->len;
1914 	if (p != NULL) {
1915 		while (n > 0) {
1916 			n--;
1917 			if ((*encoder->filter_function)(*p++, encoder) < 0) {
1918 				break;
1919 			}
1920 		}
1921 		mbfl_convert_filter_flush(encoder);
1922 		if (pc.status != 0 && mkwidth > 0) {
1923 			pc.width += mkwidth;
1924 			while (n > 0) {
1925 				if ((*encoder->filter_function)(*p++, encoder) < 0) {
1926 					break;
1927 				}
1928 				n--;
1929 			}
1930 			mbfl_convert_filter_flush(encoder);
1931 			if (pc.status != 1) {
1932 				pc.status = 10;
1933 				pc.device.pos = pc.endpos;
1934 				mbfl_convert_filter_copy(pc.decoder_backup, pc.decoder);
1935 				mbfl_convert_filter_reset(encoder, marker->no_encoding, mbfl_no_encoding_wchar);
1936 				p = marker->val;
1937 				n = marker->len;
1938 				while (n > 0) {
1939 					if ((*encoder->filter_function)(*p++, encoder) < 0) {
1940 						break;
1941 					}
1942 					n--;
1943 				}
1944 				mbfl_convert_filter_flush(encoder);
1945 			}
1946 		} else if (pc.status != 0) {
1947 			pc.device.pos = pc.endpos;
1948 			mbfl_convert_filter_copy(pc.decoder_backup, pc.decoder);
1949 		}
1950 		mbfl_convert_filter_flush(pc.decoder);
1951 	}
1952 	result = mbfl_memory_device_result(&pc.device, result);
1953 	mbfl_convert_filter_delete(encoder);
1954 	mbfl_convert_filter_delete(pc.decoder);
1955 	mbfl_convert_filter_delete(pc.decoder_backup);
1956 
1957 	return result;
1958 }
1959 
1960 mbfl_string *
mbfl_ja_jp_hantozen(mbfl_string * string,mbfl_string * result,int mode)1961 mbfl_ja_jp_hantozen(
1962     mbfl_string *string,
1963     mbfl_string *result,
1964     int mode)
1965 {
1966 	int n;
1967 	unsigned char *p;
1968 	const mbfl_encoding *encoding;
1969 	mbfl_memory_device device;
1970 	mbfl_convert_filter *decoder = NULL;
1971 	mbfl_convert_filter *encoder = NULL;
1972 	mbfl_convert_filter *tl_filter = NULL;
1973 	mbfl_convert_filter *next_filter = NULL;
1974 	mbfl_filt_tl_jisx0201_jisx0208_param *param = NULL;
1975 
1976 	/* validate parameters */
1977 	if (string == NULL || result == NULL) {
1978 		return NULL;
1979 	}
1980 
1981 	encoding = mbfl_no2encoding(string->no_encoding);
1982 	if (encoding == NULL) {
1983 		return NULL;
1984 	}
1985 
1986 	mbfl_memory_device_init(&device, string->len, 0);
1987 	mbfl_string_init(result);
1988 
1989 	result->no_language = string->no_language;
1990 	result->no_encoding = string->no_encoding;
1991 
1992 	decoder = mbfl_convert_filter_new(
1993 		mbfl_no_encoding_wchar,
1994 		string->no_encoding,
1995 		mbfl_memory_device_output, 0, &device);
1996 	if (decoder == NULL) {
1997 		goto out;
1998 	}
1999 	next_filter = decoder;
2000 
2001 	param =
2002 		(mbfl_filt_tl_jisx0201_jisx0208_param *)mbfl_malloc(sizeof(mbfl_filt_tl_jisx0201_jisx0208_param));
2003 	if (param == NULL) {
2004 		goto out;
2005 	}
2006 
2007 	param->mode = mode;
2008 
2009 	tl_filter = mbfl_convert_filter_new2(
2010 		&vtbl_tl_jisx0201_jisx0208,
2011 		(int(*)(int, void*))next_filter->filter_function,
2012 		(int(*)(void*))next_filter->filter_flush,
2013 		next_filter);
2014 	if (tl_filter == NULL) {
2015 		mbfl_free(param);
2016 		goto out;
2017 	}
2018 
2019 	tl_filter->opaque = param;
2020 	next_filter = tl_filter;
2021 
2022 	encoder = mbfl_convert_filter_new(
2023 		string->no_encoding,
2024 		mbfl_no_encoding_wchar,
2025 		(int(*)(int, void*))next_filter->filter_function,
2026 		(int(*)(void*))next_filter->filter_flush,
2027 		next_filter);
2028 	if (encoder == NULL) {
2029 		goto out;
2030 	}
2031 
2032 	/* feed data */
2033 	p = string->val;
2034 	n = string->len;
2035 	if (p != NULL) {
2036 		while (n > 0) {
2037 			if ((*encoder->filter_function)(*p++, encoder) < 0) {
2038 				break;
2039 			}
2040 			n--;
2041 		}
2042 	}
2043 
2044 	mbfl_convert_filter_flush(encoder);
2045 	result = mbfl_memory_device_result(&device, result);
2046 out:
2047 	if (tl_filter != NULL) {
2048 		if (tl_filter->opaque != NULL) {
2049 			mbfl_free(tl_filter->opaque);
2050 		}
2051 		mbfl_convert_filter_delete(tl_filter);
2052 	}
2053 
2054 	if (decoder != NULL) {
2055 		mbfl_convert_filter_delete(decoder);
2056 	}
2057 
2058 	if (encoder != NULL) {
2059 		mbfl_convert_filter_delete(encoder);
2060 	}
2061 
2062 	return result;
2063 }
2064 
2065 
2066 /*
2067  *  MIME header encode
2068  */
2069 struct mime_header_encoder_data {
2070 	mbfl_convert_filter *conv1_filter;
2071 	mbfl_convert_filter *block_filter;
2072 	mbfl_convert_filter *conv2_filter;
2073 	mbfl_convert_filter *conv2_filter_backup;
2074 	mbfl_convert_filter *encod_filter;
2075 	mbfl_convert_filter *encod_filter_backup;
2076 	mbfl_memory_device outdev;
2077 	mbfl_memory_device tmpdev;
2078 	int status1;
2079 	int status2;
2080 	int prevpos;
2081 	int linehead;
2082 	int firstindent;
2083 	int encnamelen;
2084 	int lwsplen;
2085 	char encname[128];
2086 	char lwsp[16];
2087 };
2088 
2089 static int
mime_header_encoder_block_collector(int c,void * data)2090 mime_header_encoder_block_collector(int c, void *data)
2091 {
2092 	int n;
2093 	struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data;
2094 
2095 	switch (pe->status2) {
2096 	case 1:	/* encoded word */
2097 		pe->prevpos = pe->outdev.pos;
2098 		mbfl_convert_filter_copy(pe->conv2_filter, pe->conv2_filter_backup);
2099 		mbfl_convert_filter_copy(pe->encod_filter, pe->encod_filter_backup);
2100 		(*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
2101 		(*pe->conv2_filter->filter_flush)(pe->conv2_filter);
2102 		(*pe->encod_filter->filter_flush)(pe->encod_filter);
2103 		n = pe->outdev.pos - pe->linehead + pe->firstindent;
2104 		pe->outdev.pos = pe->prevpos;
2105 		mbfl_convert_filter_copy(pe->conv2_filter_backup, pe->conv2_filter);
2106 		mbfl_convert_filter_copy(pe->encod_filter_backup, pe->encod_filter);
2107 		if (n >= 74) {
2108 			(*pe->conv2_filter->filter_flush)(pe->conv2_filter);
2109 			(*pe->encod_filter->filter_flush)(pe->encod_filter);
2110 			mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2);	/* ?= */
2111 			mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);
2112 			pe->linehead = pe->outdev.pos;
2113 			pe->firstindent = 0;
2114 			mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen);
2115 			c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
2116 		} else {
2117 			c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
2118 		}
2119 		break;
2120 
2121 	default:
2122 		mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen);
2123 		c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter);
2124 		pe->status2 = 1;
2125 		break;
2126 	}
2127 
2128 	return c;
2129 }
2130 
2131 static int
mime_header_encoder_collector(int c,void * data)2132 mime_header_encoder_collector(int c, void *data)
2133 {
2134 	static int qp_table[256] = {
2135 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */
2136 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */
2137 		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2138 		0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 1, 0, 1, /* 0x10 */
2139 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2140 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x50 */
2141 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
2142 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x70 */
2143 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */
2144 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 */
2145 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xA0 */
2146 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xB0 */
2147 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 */
2148 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 */
2149 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xE0 */
2150 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  /* 0xF0 */
2151 	};
2152 
2153 	int n;
2154 	struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data;
2155 
2156 	switch (pe->status1) {
2157 	case 11:	/* encoded word */
2158 		(*pe->block_filter->filter_function)(c, pe->block_filter);
2159 		break;
2160 
2161 	default:	/* ASCII */
2162 		if (c <= 0x00ff && !qp_table[(c & 0xff)]) { /* ordinary characters */
2163 			mbfl_memory_device_output(c, &pe->tmpdev);
2164 			pe->status1 = 1;
2165 		} else if (pe->status1 == 0 && c == 0x20) {	/* repeat SPACE */
2166 			mbfl_memory_device_output(c, &pe->tmpdev);
2167 		} else {
2168 			if (pe->tmpdev.pos < 74 && c == 0x20) {
2169 				n = pe->outdev.pos - pe->linehead + pe->tmpdev.pos + pe->firstindent;
2170 				if (n > 74) {
2171 					mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);		/* LWSP */
2172 					pe->linehead = pe->outdev.pos;
2173 					pe->firstindent = 0;
2174 				} else if (pe->outdev.pos > 0) {
2175 					mbfl_memory_device_output(0x20, &pe->outdev);
2176 				}
2177 				mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev);
2178 				mbfl_memory_device_reset(&pe->tmpdev);
2179 				pe->status1 = 0;
2180 			} else {
2181 				n = pe->outdev.pos - pe->linehead + pe->encnamelen + pe->firstindent;
2182 				if (n > 60)  {
2183 					mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);		/* LWSP */
2184 					pe->linehead = pe->outdev.pos;
2185 					pe->firstindent = 0;
2186 				} else if (pe->outdev.pos > 0)  {
2187 					mbfl_memory_device_output(0x20, &pe->outdev);
2188 				}
2189 				mbfl_convert_filter_devcat(pe->block_filter, &pe->tmpdev);
2190 				mbfl_memory_device_reset(&pe->tmpdev);
2191 				(*pe->block_filter->filter_function)(c, pe->block_filter);
2192 				pe->status1 = 11;
2193 			}
2194 		}
2195 		break;
2196 	}
2197 
2198 	return c;
2199 }
2200 
2201 mbfl_string *
mime_header_encoder_result(struct mime_header_encoder_data * pe,mbfl_string * result)2202 mime_header_encoder_result(struct mime_header_encoder_data *pe, mbfl_string *result)
2203 {
2204 	if (pe->status1 >= 10) {
2205 		(*pe->conv2_filter->filter_flush)(pe->conv2_filter);
2206 		(*pe->encod_filter->filter_flush)(pe->encod_filter);
2207 		mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2);		/* ?= */
2208 	} else if (pe->tmpdev.pos > 0) {
2209 		if (pe->outdev.pos > 0) {
2210 			if ((pe->outdev.pos - pe->linehead + pe->tmpdev.pos) > 74) {
2211 				mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen);
2212 			} else {
2213 				mbfl_memory_device_output(0x20, &pe->outdev);
2214 			}
2215 		}
2216 		mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev);
2217 	}
2218 	mbfl_memory_device_reset(&pe->tmpdev);
2219 	pe->prevpos = 0;
2220 	pe->linehead = 0;
2221 	pe->status1 = 0;
2222 	pe->status2 = 0;
2223 
2224 	return mbfl_memory_device_result(&pe->outdev, result);
2225 }
2226 
2227 struct mime_header_encoder_data*
mime_header_encoder_new(enum mbfl_no_encoding incode,enum mbfl_no_encoding outcode,enum mbfl_no_encoding transenc)2228 mime_header_encoder_new(
2229     enum mbfl_no_encoding incode,
2230     enum mbfl_no_encoding outcode,
2231     enum mbfl_no_encoding transenc)
2232 {
2233 	int n;
2234 	const char *s;
2235 	const mbfl_encoding *outencoding;
2236 	struct mime_header_encoder_data *pe;
2237 
2238 	/* get output encoding and check MIME charset name */
2239 	outencoding = mbfl_no2encoding(outcode);
2240 	if (outencoding == NULL || outencoding->mime_name == NULL || outencoding->mime_name[0] == '\0') {
2241 		return NULL;
2242 	}
2243 
2244 	pe = (struct mime_header_encoder_data*)mbfl_malloc(sizeof(struct mime_header_encoder_data));
2245 	if (pe == NULL) {
2246 		return NULL;
2247 	}
2248 
2249 	mbfl_memory_device_init(&pe->outdev, 0, 0);
2250 	mbfl_memory_device_init(&pe->tmpdev, 0, 0);
2251 	pe->prevpos = 0;
2252 	pe->linehead = 0;
2253 	pe->firstindent = 0;
2254 	pe->status1 = 0;
2255 	pe->status2 = 0;
2256 
2257 	/* make the encoding description string  exp. "=?ISO-2022-JP?B?" */
2258 	n = 0;
2259 	pe->encname[n++] = 0x3d;
2260 	pe->encname[n++] = 0x3f;
2261 	s = outencoding->mime_name;
2262 	while (*s) {
2263 		pe->encname[n++] = *s++;
2264 	}
2265 	pe->encname[n++] = 0x3f;
2266 	if (transenc == mbfl_no_encoding_qprint) {
2267 		pe->encname[n++] = 0x51;
2268 	} else {
2269 		pe->encname[n++] = 0x42;
2270 		transenc = mbfl_no_encoding_base64;
2271 	}
2272 	pe->encname[n++] = 0x3f;
2273 	pe->encname[n] = '\0';
2274 	pe->encnamelen = n;
2275 
2276 	n = 0;
2277 	pe->lwsp[n++] = 0x0d;
2278 	pe->lwsp[n++] = 0x0a;
2279 	pe->lwsp[n++] = 0x20;
2280 	pe->lwsp[n] = '\0';
2281 	pe->lwsplen = n;
2282 
2283 	/* transfer encode filter */
2284 	pe->encod_filter = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev));
2285 	pe->encod_filter_backup = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev));
2286 
2287 	/* Output code filter */
2288 	pe->conv2_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter);
2289 	pe->conv2_filter_backup = mbfl_convert_filter_new(mbfl_no_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter);
2290 
2291 	/* encoded block filter */
2292 	pe->block_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, mbfl_no_encoding_wchar, mime_header_encoder_block_collector, 0, pe);
2293 
2294 	/* Input code filter */
2295 	pe->conv1_filter = mbfl_convert_filter_new(incode, mbfl_no_encoding_wchar, mime_header_encoder_collector, 0, pe);
2296 
2297 	if (pe->encod_filter == NULL ||
2298 	    pe->encod_filter_backup == NULL ||
2299 	    pe->conv2_filter == NULL ||
2300 	    pe->conv2_filter_backup == NULL ||
2301 	    pe->conv1_filter == NULL) {
2302 		mime_header_encoder_delete(pe);
2303 		return NULL;
2304 	}
2305 
2306 	if (transenc == mbfl_no_encoding_qprint) {
2307 		pe->encod_filter->status |= MBFL_QPRINT_STS_MIME_HEADER;
2308 		pe->encod_filter_backup->status |= MBFL_QPRINT_STS_MIME_HEADER;
2309 	} else {
2310 		pe->encod_filter->status |= MBFL_BASE64_STS_MIME_HEADER;
2311 		pe->encod_filter_backup->status |= MBFL_BASE64_STS_MIME_HEADER;
2312 	}
2313 
2314 	return pe;
2315 }
2316 
2317 void
mime_header_encoder_delete(struct mime_header_encoder_data * pe)2318 mime_header_encoder_delete(struct mime_header_encoder_data *pe)
2319 {
2320 	if (pe) {
2321 		mbfl_convert_filter_delete(pe->conv1_filter);
2322 		mbfl_convert_filter_delete(pe->block_filter);
2323 		mbfl_convert_filter_delete(pe->conv2_filter);
2324 		mbfl_convert_filter_delete(pe->conv2_filter_backup);
2325 		mbfl_convert_filter_delete(pe->encod_filter);
2326 		mbfl_convert_filter_delete(pe->encod_filter_backup);
2327 		mbfl_memory_device_clear(&pe->outdev);
2328 		mbfl_memory_device_clear(&pe->tmpdev);
2329 		mbfl_free((void*)pe);
2330 	}
2331 }
2332 
2333 int
mime_header_encoder_feed(int c,struct mime_header_encoder_data * pe)2334 mime_header_encoder_feed(int c, struct mime_header_encoder_data *pe)
2335 {
2336 	return (*pe->conv1_filter->filter_function)(c, pe->conv1_filter);
2337 }
2338 
2339 mbfl_string *
mbfl_mime_header_encode(mbfl_string * string,mbfl_string * result,enum mbfl_no_encoding outcode,enum mbfl_no_encoding encoding,const char * linefeed,int indent)2340 mbfl_mime_header_encode(
2341     mbfl_string *string,
2342     mbfl_string *result,
2343     enum mbfl_no_encoding outcode,
2344     enum mbfl_no_encoding encoding,
2345     const char *linefeed,
2346     int indent)
2347 {
2348 	int n;
2349 	unsigned char *p;
2350 	struct mime_header_encoder_data *pe;
2351 
2352 	mbfl_string_init(result);
2353 	result->no_language = string->no_language;
2354 	result->no_encoding = mbfl_no_encoding_ascii;
2355 
2356 	pe = mime_header_encoder_new(string->no_encoding, outcode, encoding);
2357 	if (pe == NULL) {
2358 		return NULL;
2359 	}
2360 
2361 	if (linefeed != NULL) {
2362 		n = 0;
2363 		while (*linefeed && n < 8) {
2364 			pe->lwsp[n++] = *linefeed++;
2365 		}
2366 		pe->lwsp[n++] = 0x20;
2367 		pe->lwsp[n] = '\0';
2368 		pe->lwsplen = n;
2369 	}
2370 	if (indent > 0 && indent < 74) {
2371 		pe->firstindent = indent;
2372 	}
2373 
2374 	n = string->len;
2375 	p = string->val;
2376 	while (n > 0) {
2377 		(*pe->conv1_filter->filter_function)(*p++, pe->conv1_filter);
2378 		n--;
2379 	}
2380 
2381 	result = mime_header_encoder_result(pe, result);
2382 	mime_header_encoder_delete(pe);
2383 
2384 	return result;
2385 }
2386 
2387 
2388 /*
2389  *  MIME header decode
2390  */
2391 struct mime_header_decoder_data {
2392 	mbfl_convert_filter *deco_filter;
2393 	mbfl_convert_filter *conv1_filter;
2394 	mbfl_convert_filter *conv2_filter;
2395 	mbfl_memory_device outdev;
2396 	mbfl_memory_device tmpdev;
2397 	int cspos;
2398 	int status;
2399 	enum mbfl_no_encoding encoding;
2400 	enum mbfl_no_encoding incode;
2401 	enum mbfl_no_encoding outcode;
2402 };
2403 
2404 static int
mime_header_decoder_collector(int c,void * data)2405 mime_header_decoder_collector(int c, void* data)
2406 {
2407 	const mbfl_encoding *encoding;
2408 	struct mime_header_decoder_data *pd = (struct mime_header_decoder_data*)data;
2409 
2410 	switch (pd->status) {
2411 	case 1:
2412 		if (c == 0x3f) {		/* ? */
2413 			mbfl_memory_device_output(c, &pd->tmpdev);
2414 			pd->cspos = pd->tmpdev.pos;
2415 			pd->status = 2;
2416 		} else {
2417 			mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2418 			mbfl_memory_device_reset(&pd->tmpdev);
2419 			if (c == 0x3d) {		/* = */
2420 				mbfl_memory_device_output(c, &pd->tmpdev);
2421 			} else if (c == 0x0d || c == 0x0a) {	/* CR or LF */
2422 				pd->status = 9;
2423 			} else {
2424 				(*pd->conv1_filter->filter_function)(c, pd->conv1_filter);
2425 				pd->status = 0;
2426 			}
2427 		}
2428 		break;
2429 	case 2:		/* store charset string */
2430 		if (c == 0x3f) {		/* ? */
2431 			/* identify charset */
2432 			mbfl_memory_device_output('\0', &pd->tmpdev);
2433 			encoding = mbfl_name2encoding((const char *)&pd->tmpdev.buffer[pd->cspos]);
2434 			if (encoding != NULL) {
2435 				pd->incode = encoding->no_encoding;
2436 				pd->status = 3;
2437 			}
2438 			mbfl_memory_device_unput(&pd->tmpdev);
2439 			mbfl_memory_device_output(c, &pd->tmpdev);
2440 		} else {
2441 			mbfl_memory_device_output(c, &pd->tmpdev);
2442 			if (pd->tmpdev.pos > 100) {		/* too long charset string */
2443 				pd->status = 0;
2444 			} else if (c == 0x0d || c == 0x0a) {	/* CR or LF */
2445 				mbfl_memory_device_unput(&pd->tmpdev);
2446 				pd->status = 9;
2447 			}
2448 			if (pd->status != 2) {
2449 				mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2450 				mbfl_memory_device_reset(&pd->tmpdev);
2451 			}
2452 		}
2453 		break;
2454 	case 3:		/* identify encoding */
2455 		mbfl_memory_device_output(c, &pd->tmpdev);
2456 		if (c == 0x42 || c == 0x62) {		/* 'B' or 'b' */
2457 			pd->encoding = mbfl_no_encoding_base64;
2458 			pd->status = 4;
2459 		} else if (c == 0x51 || c == 0x71) {	/* 'Q' or 'q' */
2460 			pd->encoding = mbfl_no_encoding_qprint;
2461 			pd->status = 4;
2462 		} else {
2463 			if (c == 0x0d || c == 0x0a) {	/* CR or LF */
2464 				mbfl_memory_device_unput(&pd->tmpdev);
2465 				pd->status = 9;
2466 			} else {
2467 				pd->status = 0;
2468 			}
2469 			mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2470 			mbfl_memory_device_reset(&pd->tmpdev);
2471 		}
2472 		break;
2473 	case 4:		/* reset filter */
2474 		mbfl_memory_device_output(c, &pd->tmpdev);
2475 		if (c == 0x3f) {		/* ? */
2476 			/* charset convert filter */
2477 			mbfl_convert_filter_reset(pd->conv1_filter, pd->incode, mbfl_no_encoding_wchar);
2478 			/* decode filter */
2479 			mbfl_convert_filter_reset(pd->deco_filter, pd->encoding, mbfl_no_encoding_8bit);
2480 			pd->status = 5;
2481 		} else {
2482 			if (c == 0x0d || c == 0x0a) {	/* CR or LF */
2483 				mbfl_memory_device_unput(&pd->tmpdev);
2484 				pd->status = 9;
2485 			} else {
2486 				pd->status = 0;
2487 			}
2488 			mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2489 		}
2490 		mbfl_memory_device_reset(&pd->tmpdev);
2491 		break;
2492 	case 5:		/* encoded block */
2493 		if (c == 0x3f) {		/* ? */
2494 			pd->status = 6;
2495 		} else {
2496 			(*pd->deco_filter->filter_function)(c, pd->deco_filter);
2497 		}
2498 		break;
2499 	case 6:		/* check end position */
2500 		if (c == 0x3d) {		/* = */
2501 			/* flush and reset filter */
2502 			(*pd->deco_filter->filter_flush)(pd->deco_filter);
2503 			(*pd->conv1_filter->filter_flush)(pd->conv1_filter);
2504 			mbfl_convert_filter_reset(pd->conv1_filter, mbfl_no_encoding_ascii, mbfl_no_encoding_wchar);
2505 			pd->status = 7;
2506 		} else {
2507 			(*pd->deco_filter->filter_function)(0x3f, pd->deco_filter);
2508 			if (c != 0x3f) {		/* ? */
2509 				(*pd->deco_filter->filter_function)(c, pd->deco_filter);
2510 				pd->status = 5;
2511 			}
2512 		}
2513 		break;
2514 	case 7:		/* after encoded block */
2515 		if (c == 0x0d || c == 0x0a) {	/* CR LF */
2516 			pd->status = 8;
2517 		} else {
2518 			mbfl_memory_device_output(c, &pd->tmpdev);
2519 			if (c == 0x3d) {		/* = */
2520 				pd->status = 1;
2521 			} else if (c != 0x20 && c != 0x09) {		/* not space */
2522 				mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2523 				mbfl_memory_device_reset(&pd->tmpdev);
2524 				pd->status = 0;
2525 			}
2526 		}
2527 		break;
2528 	case 8:		/* folding */
2529 	case 9:		/* folding */
2530 		if (c != 0x0d && c != 0x0a && c != 0x20 && c != 0x09) {
2531 			if (c == 0x3d) {		/* = */
2532 				if (pd->status == 8) {
2533 					mbfl_memory_device_output(0x20, &pd->tmpdev);	/* SPACE */
2534 				} else {
2535 					(*pd->conv1_filter->filter_function)(0x20, pd->conv1_filter);
2536 				}
2537 				mbfl_memory_device_output(c, &pd->tmpdev);
2538 				pd->status = 1;
2539 			} else {
2540 				mbfl_memory_device_output(0x20, &pd->tmpdev);
2541 				mbfl_memory_device_output(c, &pd->tmpdev);
2542 				mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2543 				mbfl_memory_device_reset(&pd->tmpdev);
2544 				pd->status = 0;
2545 			}
2546 		}
2547 		break;
2548 	default:		/* non encoded block */
2549 		if (c == 0x0d || c == 0x0a) {	/* CR LF */
2550 			pd->status = 9;
2551 		} else if (c == 0x3d) {		/* = */
2552 			mbfl_memory_device_output(c, &pd->tmpdev);
2553 			pd->status = 1;
2554 		} else {
2555 			(*pd->conv1_filter->filter_function)(c, pd->conv1_filter);
2556 		}
2557 		break;
2558 	}
2559 
2560 	return c;
2561 }
2562 
2563 mbfl_string *
mime_header_decoder_result(struct mime_header_decoder_data * pd,mbfl_string * result)2564 mime_header_decoder_result(struct mime_header_decoder_data *pd, mbfl_string *result)
2565 {
2566 	switch (pd->status) {
2567 	case 1:
2568 	case 2:
2569 	case 3:
2570 	case 4:
2571 	case 7:
2572 	case 8:
2573 	case 9:
2574 		mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev);
2575 		break;
2576 	case 5:
2577 	case 6:
2578 		(*pd->deco_filter->filter_flush)(pd->deco_filter);
2579 		(*pd->conv1_filter->filter_flush)(pd->conv1_filter);
2580 		break;
2581 	}
2582 	(*pd->conv2_filter->filter_flush)(pd->conv2_filter);
2583 	mbfl_memory_device_reset(&pd->tmpdev);
2584 	pd->status = 0;
2585 
2586 	return mbfl_memory_device_result(&pd->outdev, result);
2587 }
2588 
2589 struct mime_header_decoder_data*
mime_header_decoder_new(enum mbfl_no_encoding outcode)2590 mime_header_decoder_new(enum mbfl_no_encoding outcode)
2591 {
2592 	struct mime_header_decoder_data *pd;
2593 
2594 	pd = (struct mime_header_decoder_data*)mbfl_malloc(sizeof(struct mime_header_decoder_data));
2595 	if (pd == NULL) {
2596 		return NULL;
2597 	}
2598 
2599 	mbfl_memory_device_init(&pd->outdev, 0, 0);
2600 	mbfl_memory_device_init(&pd->tmpdev, 0, 0);
2601 	pd->cspos = 0;
2602 	pd->status = 0;
2603 	pd->encoding = mbfl_no_encoding_pass;
2604 	pd->incode = mbfl_no_encoding_ascii;
2605 	pd->outcode = outcode;
2606 	/* charset convert filter */
2607 	pd->conv2_filter = mbfl_convert_filter_new(mbfl_no_encoding_wchar, pd->outcode, mbfl_memory_device_output, 0, &pd->outdev);
2608 	pd->conv1_filter = mbfl_convert_filter_new(pd->incode, mbfl_no_encoding_wchar, mbfl_filter_output_pipe, 0, pd->conv2_filter);
2609 	/* decode filter */
2610 	pd->deco_filter = mbfl_convert_filter_new(pd->encoding, mbfl_no_encoding_8bit, mbfl_filter_output_pipe, 0, pd->conv1_filter);
2611 
2612 	if (pd->conv1_filter == NULL || pd->conv2_filter == NULL || pd->deco_filter == NULL) {
2613 		mime_header_decoder_delete(pd);
2614 		return NULL;
2615 	}
2616 
2617 	return pd;
2618 }
2619 
2620 void
mime_header_decoder_delete(struct mime_header_decoder_data * pd)2621 mime_header_decoder_delete(struct mime_header_decoder_data *pd)
2622 {
2623 	if (pd) {
2624 		mbfl_convert_filter_delete(pd->conv2_filter);
2625 		mbfl_convert_filter_delete(pd->conv1_filter);
2626 		mbfl_convert_filter_delete(pd->deco_filter);
2627 		mbfl_memory_device_clear(&pd->outdev);
2628 		mbfl_memory_device_clear(&pd->tmpdev);
2629 		mbfl_free((void*)pd);
2630 	}
2631 }
2632 
2633 int
mime_header_decoder_feed(int c,struct mime_header_decoder_data * pd)2634 mime_header_decoder_feed(int c, struct mime_header_decoder_data *pd)
2635 {
2636 	return mime_header_decoder_collector(c, pd);
2637 }
2638 
2639 mbfl_string *
mbfl_mime_header_decode(mbfl_string * string,mbfl_string * result,enum mbfl_no_encoding outcode)2640 mbfl_mime_header_decode(
2641     mbfl_string *string,
2642     mbfl_string *result,
2643     enum mbfl_no_encoding outcode)
2644 {
2645 	int n;
2646 	unsigned char *p;
2647 	struct mime_header_decoder_data *pd;
2648 
2649 	mbfl_string_init(result);
2650 	result->no_language = string->no_language;
2651 	result->no_encoding = outcode;
2652 
2653 	pd = mime_header_decoder_new(outcode);
2654 	if (pd == NULL) {
2655 		return NULL;
2656 	}
2657 
2658 	/* feed data */
2659 	n = string->len;
2660 	p = string->val;
2661 	while (n > 0) {
2662 		mime_header_decoder_collector(*p++, pd);
2663 		n--;
2664 	}
2665 
2666 	result = mime_header_decoder_result(pd, result);
2667 	mime_header_decoder_delete(pd);
2668 
2669 	return result;
2670 }
2671 
2672 
2673 
2674 /*
2675  *  convert HTML numeric entity
2676  */
2677 struct collector_htmlnumericentity_data {
2678 	mbfl_convert_filter *decoder;
2679 	int status;
2680 	int cache;
2681 	int digit;
2682 	int *convmap;
2683 	int mapsize;
2684 };
2685 
2686 static int
collector_encode_htmlnumericentity(int c,void * data)2687 collector_encode_htmlnumericentity(int c, void *data)
2688 {
2689 	struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)data;
2690 	int f, n, s, r, d, size, *mapelm;
2691 
2692 	size = pc->mapsize;
2693 	f = 0;
2694 	n = 0;
2695 	while (n < size) {
2696 		mapelm = &(pc->convmap[n*4]);
2697 		if (c >= mapelm[0] && c <= mapelm[1]) {
2698 			s = (c + mapelm[2]) & mapelm[3];
2699 			if (s >= 0) {
2700 				(*pc->decoder->filter_function)(0x26, pc->decoder);	/* '&' */
2701 				(*pc->decoder->filter_function)(0x23, pc->decoder);	/* '#' */
2702 				r = 100000000;
2703 				s %= r;
2704 				while (r > 0) {
2705 					d = s/r;
2706 					if (d || f) {
2707 						f = 1;
2708 						s %= r;
2709 						(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
2710 					}
2711 					r /= 10;
2712 				}
2713 				if (!f) {
2714 					f = 1;
2715 					(*pc->decoder->filter_function)(mbfl_hexchar_table[0], pc->decoder);
2716 				}
2717 				(*pc->decoder->filter_function)(0x3b, pc->decoder);		/* ';' */
2718 			}
2719 		}
2720 		if (f) {
2721 			break;
2722 		}
2723 		n++;
2724 	}
2725 	if (!f) {
2726 		(*pc->decoder->filter_function)(c, pc->decoder);
2727 	}
2728 
2729 	return c;
2730 }
2731 
2732 static int
collector_decode_htmlnumericentity(int c,void * data)2733 collector_decode_htmlnumericentity(int c, void *data)
2734 {
2735 	struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)data;
2736 	int f, n, s, r, d, size, *mapelm;
2737 
2738 	switch (pc->status) {
2739 	case 1:
2740 		if (c == 0x23) {	/* '#' */
2741 			pc->status = 2;
2742 		} else {
2743 			pc->status = 0;
2744 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2745 			(*pc->decoder->filter_function)(c, pc->decoder);
2746 		}
2747 		break;
2748 	case 2:
2749 		if (c == 0x78) {	/* 'x' */
2750 			pc->status = 4;
2751 		} else if (c >= 0x30 && c <= 0x39) { /* '0' - '9' */
2752 			pc->cache = c - 0x30;
2753 			pc->status = 3;
2754 			pc->digit = 1;
2755 		} else {
2756 			pc->status = 0;
2757 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2758 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2759 			(*pc->decoder->filter_function)(c, pc->decoder);
2760 		}
2761 		break;
2762 	case 3:
2763 		s = 0;
2764 		f = 0;
2765 		if (c >= 0x30 && c <= 0x39) {	/* '0' - '9' */
2766 			if (pc->digit > 9) {
2767 				pc->status = 0;
2768 				s = pc->cache;
2769 				f = 1;
2770 			} else {
2771 				s = pc->cache*10 + c - 0x30;
2772 				pc->cache = s;
2773 				pc->digit++;
2774 			}
2775 		} else {
2776 			pc->status = 0;
2777 			s = pc->cache;
2778 			f = 1;
2779 			n = 0;
2780 			size = pc->mapsize;
2781 			while (n < size) {
2782 				mapelm = &(pc->convmap[n*4]);
2783 				d = s - mapelm[2];
2784 				if (d >= mapelm[0] && d <= mapelm[1]) {
2785 					f = 0;
2786 					(*pc->decoder->filter_function)(d, pc->decoder);
2787 					if (c != 0x3b) {	/* ';' */
2788 						(*pc->decoder->filter_function)(c, pc->decoder);
2789 					}
2790 					break;
2791 				}
2792 				n++;
2793 			}
2794 		}
2795 		if (f) {
2796 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2797 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2798 			r = 1;
2799 			n = pc->digit;
2800 			while (n > 0) {
2801 				r *= 10;
2802 				n--;
2803 			}
2804 			s %= r;
2805 			r /= 10;
2806 			while (r > 0) {
2807 				d = s/r;
2808 				s %= r;
2809 				r /= 10;
2810 				(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
2811 			}
2812 			(*pc->decoder->filter_function)(c, pc->decoder);
2813 		}
2814 		break;
2815 	case 4:
2816 		if (c >= 0x30 && c <= 0x39) { /* '0' - '9' */
2817 			pc->cache = c - 0x30;
2818 			pc->status = 5;
2819 			pc->digit = 1;
2820 		} else if (c >= 0x41 && c <= 0x46) { /* 'A' - 'F'  */
2821 			pc->cache = c - 0x41 + 10;
2822 			pc->status = 5;
2823 			pc->digit = 1;
2824 		} else if (c >= 0x61 && c <= 0x66) { /* 'a' - 'f'  */
2825 			pc->cache = c - 0x61 + 10;
2826 			pc->status = 5;
2827 			pc->digit = 1;
2828 		} else {
2829 			pc->status = 0;
2830 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2831 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2832 			(*pc->decoder->filter_function)(0x78, pc->decoder);		/* 'x' */
2833 			(*pc->decoder->filter_function)(c, pc->decoder);
2834 		}
2835 		break;
2836 	case 5:
2837 		s = 0;
2838 		f = 0;
2839 		if ((c >= 0x30 && c <= 0x39) ||
2840 			(c >= 0x41 && c <= 0x46) ||
2841 			(c >= 0x61 && c <= 0x66)) {	/* '0' - '9' or 'a' - 'f'  */
2842 			if (pc->digit > 9) {
2843 				pc->status = 0;
2844 				s = pc->cache;
2845 				f = 1;
2846 			} else {
2847 				if (c >= 0x30 && c <= 0x39) {
2848 					s = pc->cache*16 + (c - 0x30);
2849 				} else if (c >= 0x41 && c <= 0x46)  {
2850 					s = pc->cache*16 + (c - 0x41 + 10);
2851 				} else {
2852 					s = pc->cache*16 + (c - 0x61 + 10);
2853 				}
2854 				pc->cache = s;
2855 				pc->digit++;
2856 			}
2857 		} else {
2858 			pc->status = 0;
2859 			s = pc->cache;
2860 			f = 1;
2861 			n = 0;
2862 			size = pc->mapsize;
2863 			while (n < size) {
2864 				mapelm = &(pc->convmap[n*4]);
2865 				d = s - mapelm[2];
2866 				if (d >= mapelm[0] && d <= mapelm[1]) {
2867 					f = 0;
2868 					(*pc->decoder->filter_function)(d, pc->decoder);
2869 					if (c != 0x3b) {	/* ';' */
2870 						(*pc->decoder->filter_function)(c, pc->decoder);
2871 					}
2872 					break;
2873 				}
2874 				n++;
2875 			}
2876 		}
2877 		if (f) {
2878 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2879 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2880 			(*pc->decoder->filter_function)(0x78, pc->decoder);		/* 'x' */
2881 			r = 1;
2882 			n = pc->digit;
2883 			while (n > 0) {
2884 				r *= 16;
2885 				n--;
2886 			}
2887 			s %= r;
2888 			r /= 16;
2889 			while (r > 0) {
2890 				d = s/r;
2891 				s %= r;
2892 				r /= 16;
2893 				(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
2894 			}
2895 			(*pc->decoder->filter_function)(c, pc->decoder);
2896 		}
2897 		break;
2898 	default:
2899 		if (c == 0x26) {	/* '&' */
2900 			pc->status = 1;
2901 		} else {
2902 			(*pc->decoder->filter_function)(c, pc->decoder);
2903 		}
2904 		break;
2905 	}
2906 
2907 	return c;
2908 }
2909 
2910 static int
collector_encode_hex_htmlnumericentity(int c,void * data)2911 collector_encode_hex_htmlnumericentity(int c, void *data)
2912 {
2913 	struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)data;
2914 	int f, n, s, r, d, size, *mapelm;
2915 
2916 	size = pc->mapsize;
2917 	f = 0;
2918 	n = 0;
2919 	while (n < size) {
2920 		mapelm = &(pc->convmap[n*4]);
2921 		if (c >= mapelm[0] && c <= mapelm[1]) {
2922 			s = (c + mapelm[2]) & mapelm[3];
2923 			if (s >= 0) {
2924 				(*pc->decoder->filter_function)(0x26, pc->decoder);	/* '&' */
2925 				(*pc->decoder->filter_function)(0x23, pc->decoder);	/* '#' */
2926 				(*pc->decoder->filter_function)(0x78, pc->decoder);	/* 'x' */
2927 				r = 0x1000000;
2928 				s %= r;
2929 				while (r > 0) {
2930 					d = s/r;
2931 					if (d || f) {
2932 						f = 1;
2933 						s %= r;
2934 						(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
2935 					}
2936 					r /= 16;
2937 				}
2938 				if (!f) {
2939 					f = 1;
2940 					(*pc->decoder->filter_function)(mbfl_hexchar_table[0], pc->decoder);
2941 				}
2942 				(*pc->decoder->filter_function)(0x3b, pc->decoder);		/* ';' */
2943 			}
2944 		}
2945 		if (f) {
2946 			break;
2947 		}
2948 		n++;
2949 	}
2950 	if (!f) {
2951 		(*pc->decoder->filter_function)(c, pc->decoder);
2952 	}
2953 
2954 	return c;
2955 }
2956 
mbfl_filt_decode_htmlnumericentity_flush(mbfl_convert_filter * filter)2957 int mbfl_filt_decode_htmlnumericentity_flush(mbfl_convert_filter *filter)
2958 {
2959 	struct collector_htmlnumericentity_data *pc = (struct collector_htmlnumericentity_data *)filter;
2960 	int n, s, r, d;
2961 
2962 	if (pc->status) {
2963 		switch (pc->status) {
2964 		case 1: /* '&' */
2965 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2966 			break;
2967 		case 2: /* '#' */
2968 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2969 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2970 			break;
2971 		case 3: /* '0'-'9' */
2972 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2973 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2974 
2975 			s = pc->cache;
2976 			r = 1;
2977 			n = pc->digit;
2978 			while (n > 0) {
2979 				r *= 10;
2980 				n--;
2981 			}
2982 			s %= r;
2983 			r /= 10;
2984 			while (r > 0) {
2985 				d = s/r;
2986 				s %= r;
2987 				r /= 10;
2988 				(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
2989 			}
2990 
2991 			break;
2992 		case 4: /* 'x' */
2993 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2994 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
2995 			(*pc->decoder->filter_function)(0x78, pc->decoder);		/* 'x' */
2996 			break;
2997 		case 5: /* '0'-'9','a'-'f' */
2998 			(*pc->decoder->filter_function)(0x26, pc->decoder);		/* '&' */
2999 			(*pc->decoder->filter_function)(0x23, pc->decoder);		/* '#' */
3000 			(*pc->decoder->filter_function)(0x78, pc->decoder);		/* 'x' */
3001 
3002 			s = pc->cache;
3003 			r = 1;
3004 			n = pc->digit;
3005 			while (n > 0) {
3006 				r *= 16;
3007 				n--;
3008 			}
3009 			s %= r;
3010 			r /= 16;
3011 			while (r > 0) {
3012 				d = s/r;
3013 				s %= r;
3014 				r /= 16;
3015 				(*pc->decoder->filter_function)(mbfl_hexchar_table[d], pc->decoder);
3016 			}
3017 			break;
3018 		default:
3019 			break;
3020 		}
3021 	}
3022 
3023 	pc->status = 0;
3024 	pc->cache = 0;
3025 	pc->digit = 0;
3026 
3027 	return 0;
3028 }
3029 
3030 
3031 mbfl_string *
mbfl_html_numeric_entity(mbfl_string * string,mbfl_string * result,int * convmap,int mapsize,int type)3032 mbfl_html_numeric_entity(
3033     mbfl_string *string,
3034     mbfl_string *result,
3035     int *convmap,
3036     int mapsize,
3037     int type)
3038 {
3039 	struct collector_htmlnumericentity_data pc;
3040 	mbfl_memory_device device;
3041 	mbfl_convert_filter *encoder;
3042 	int n;
3043 	unsigned char *p;
3044 
3045 	if (string == NULL || result == NULL) {
3046 		return NULL;
3047 	}
3048 	mbfl_string_init(result);
3049 	result->no_language = string->no_language;
3050 	result->no_encoding = string->no_encoding;
3051 	mbfl_memory_device_init(&device, string->len, 0);
3052 
3053 	/* output code filter */
3054 	pc.decoder = mbfl_convert_filter_new(
3055 	    mbfl_no_encoding_wchar,
3056 	    string->no_encoding,
3057 	    mbfl_memory_device_output, 0, &device);
3058 	/* wchar filter */
3059 	if (type == 0) { /* decimal output */
3060 		encoder = mbfl_convert_filter_new(
3061 		    string->no_encoding,
3062 		    mbfl_no_encoding_wchar,
3063 		    collector_encode_htmlnumericentity, 0, &pc);
3064 	} else if (type == 2) { /* hex output */
3065 		encoder = mbfl_convert_filter_new(
3066 		    string->no_encoding,
3067 		    mbfl_no_encoding_wchar,
3068 		    collector_encode_hex_htmlnumericentity, 0, &pc);
3069 	} else { /* type == 1: decimal/hex input */
3070 		encoder = mbfl_convert_filter_new(
3071 		    string->no_encoding,
3072 		    mbfl_no_encoding_wchar,
3073 		    collector_decode_htmlnumericentity,
3074 			(int (*)(void*))mbfl_filt_decode_htmlnumericentity_flush, &pc);
3075 	}
3076 	if (pc.decoder == NULL || encoder == NULL) {
3077 		mbfl_convert_filter_delete(encoder);
3078 		mbfl_convert_filter_delete(pc.decoder);
3079 		return NULL;
3080 	}
3081 	pc.status = 0;
3082 	pc.cache = 0;
3083 	pc.digit = 0;
3084 	pc.convmap = convmap;
3085 	pc.mapsize = mapsize;
3086 
3087 	/* feed data */
3088 	p = string->val;
3089 	n = string->len;
3090 	if (p != NULL) {
3091 		while (n > 0) {
3092 			if ((*encoder->filter_function)(*p++, encoder) < 0) {
3093 				break;
3094 			}
3095 			n--;
3096 		}
3097 	}
3098 	mbfl_convert_filter_flush(encoder);
3099 	mbfl_convert_filter_flush(pc.decoder);
3100 	result = mbfl_memory_device_result(&device, result);
3101 	mbfl_convert_filter_delete(encoder);
3102 	mbfl_convert_filter_delete(pc.decoder);
3103 
3104 	return result;
3105 }
3106 
3107 /*
3108  * Local variables:
3109  * tab-width: 4
3110  * c-basic-offset: 4
3111  * End:
3112  */
3113