xref: /php-src/ext/mbstring/libmbfl/mbfl/mbfilter.c (revision aa553af9)
1 /*
2  * charset=UTF-8
3  */
4 
5 /*
6  * "streamable kanji code filter and converter"
7  *
8  * Copyright (c) 1998,1999,2000,2001 HappySize, Inc. All rights reserved.
9  *
10  * This software is released under the GNU Lesser General Public License.
11  * (Version 2.1, February 1999)
12  * Please read the following detail of the licence (in japanese).
13  *
14  * ◆使用許諾条件◆
15  *
16  * このソフトウェアは株式会社ハッピーサイズによって開発されました。株式会社ハッ
17  * ピーサイズは、著作権法および万国著作権条約の定めにより、このソフトウェアに関
18  * するすべての権利を留保する権利を持ち、ここに行使します。株式会社ハッピーサイ
19  * ズは以下に明記した条件に従って、このソフトウェアを使用する排他的ではない権利
20  * をお客様に許諾します。何人たりとも、以下の条件に反してこのソフトウェアを使用
21  * することはできません。
22  *
23  * このソフトウェアを「GNU Lesser General Public License (Version 2.1, February
24  * 1999)」に示された条件で使用することを、全ての方に許諾します。「GNU Lesser
25  * General Public License」を満たさない使用には、株式会社ハッピーサイズから書面
26  * による許諾を得る必要があります。
27  *
28  * 「GNU Lesser General Public License」の全文は以下のウェブページから取得でき
29  * ます。「GNU Lesser General Public License」とは、これまでLibrary General
30  * Public Licenseと呼ばれていたものです。
31  *     http://www.gnu.org/ --- GNUウェブサイト
32  *     http://www.gnu.org/copyleft/lesser.html --- ライセンス文面
33  * このライセンスの内容がわからない方、守れない方には使用を許諾しません。
34  *
35  * しかしながら、当社とGNUプロジェクトとの特定の関係を示唆または主張するもので
36  * はありません。
37  *
38  * ◆保証内容◆
39  *
40  * このソフトウェアは、期待された動作・機能・性能を持つことを目標として設計され
41  * 開発されていますが、これを保証するものではありません。このソフトウェアは「こ
42  * のまま」の状態で提供されており、たとえばこのソフトウェアの有用性ないし特定の
43  * 目的に合致することといった、何らかの保証内容が、明示されたり暗黙に示されてい
44  * る場合であっても、その保証は無効です。このソフトウェアを使用した結果ないし使
45  * 用しなかった結果によって、直接あるいは間接に受けた身体的な傷害、財産上の損害
46  * 、データの損失あるいはその他の全ての損害については、その損害の可能性が使用者
47  * 、当社あるいは第三者によって警告されていた場合であっても、当社はその損害の賠
48  * 償および補填を行いません。この規定は他の全ての、書面上または書面に無い保証・
49  * 契約・規定に優先します。
50  *
51  * ◆著作権者の連絡先および使用条件についての問い合わせ先◆
52  *
53  * 〒102-0073
54  * 東京都千代田区九段北1-13-5日本地所第一ビル4F
55  * 株式会社ハッピーサイズ
56  * Phone: 03-3512-3655, Fax: 03-3512-3656
57  * Email: sales@happysize.co.jp
58  * Web: http://happysize.com/
59  *
60  * ◆著者◆
61  *
62  * 金本 茂 <sgk@happysize.co.jp>
63  *
64  * ◆履歴◆
65  *
66  * 1998/11/10 sgk implementation in C++
67  * 1999/4/25  sgk Cで書きなおし。
68  * 1999/4/26  sgk 入力フィルタを実装。漢字コードを推定しながらフィルタを追加。
69  * 1999/6/??      Unicodeサポート。
70  * 1999/6/22  sgk ライセンスをLGPLに変更。
71  *
72  */
73 
74 /*
75  * Unicode support
76  *
77  * Portions copyright (c) 1999,2000,2001 by the PHP3 internationalization team.
78  * All rights reserved.
79  *
80  */
81 
82 #include <stddef.h>
83 #include <string.h>
84 
85 #include "mbfilter.h"
86 #include "mbfl_filter_output.h"
87 #include "mbfilter_8bit.h"
88 #include "mbfilter_wchar.h"
89 #include "mbstring.h"
90 #include "php_unicode.h"
91 #include "filters/mbfilter_base64.h"
92 #include "filters/mbfilter_qprint.h"
93 #include "filters/mbfilter_singlebyte.h"
94 #include "filters/mbfilter_utf8.h"
95 
96 /*
97  *  strcut
98  */
99 mbfl_string *
mbfl_strcut(mbfl_string * string,mbfl_string * result,size_t from,size_t length)100 mbfl_strcut(
101     mbfl_string *string,
102     mbfl_string *result,
103     size_t from,
104     size_t length)
105 {
106 	const mbfl_encoding *encoding = string->encoding;
107 	mbfl_memory_device device;
108 
109 	if (from >= string->len) {
110 		from = string->len;
111 	}
112 
113 	mbfl_string_init(result);
114 	result->encoding = string->encoding;
115 
116 	if ((encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2 | MBFL_ENCTYPE_WCS4)) || encoding->mblen_table != NULL) {
117 		const unsigned char *start = NULL;
118 		const unsigned char *end = NULL;
119 		unsigned char *w;
120 		size_t sz;
121 
122 		if (encoding->flag & MBFL_ENCTYPE_WCS2) {
123 			from &= -2;
124 
125 			if (length >= string->len - from) {
126 				length = string->len - from;
127 			}
128 
129 			start = string->val + from;
130 			end   = start + (length & -2);
131 		} else if (encoding->flag & MBFL_ENCTYPE_WCS4) {
132 			from &= -4;
133 
134 			if (length >= string->len - from) {
135 				length = string->len - from;
136 			}
137 
138 			start = string->val + from;
139 			end   = start + (length & -4);
140 		} else if ((encoding->flag & MBFL_ENCTYPE_SBCS)) {
141 			if (length >= string->len - from) {
142 				length = string->len - from;
143 			}
144 
145 			start = string->val + from;
146 			end = start + length;
147 		} else if (encoding->mblen_table != NULL) {
148 			const unsigned char *mbtab = encoding->mblen_table;
149 			const unsigned char *p, *q;
150 			int m;
151 
152 			/* search start position */
153 			for (m = 0, p = string->val, q = p + from;
154 					p < q; p += (m = mbtab[*p]));
155 
156 			if (p > q) {
157 				p -= m;
158 			}
159 
160 			start = p;
161 
162 			/* search end position */
163 			if (length >= string->len - (start - string->val)) {
164 				end = string->val + string->len;
165 			} else {
166 				for (q = p + length; p < q; p += (m = mbtab[*p]));
167 
168 				if (p > q) {
169 					p -= m;
170 				}
171 				end = p;
172 			}
173 		} else {
174 			/* never reached */
175 			return NULL;
176 		}
177 
178 		/* allocate memory and copy string */
179 		sz = end - start;
180 		w = ecalloc(sz + 8, sizeof(unsigned char));
181 
182 		memcpy(w, start, sz);
183 		w[sz] = '\0';
184 		w[sz + 1] = '\0';
185 		w[sz + 2] = '\0';
186 		w[sz + 3] = '\0';
187 
188 		result->val = w;
189 		result->len = sz;
190 	} else {
191 		mbfl_convert_filter *encoder     = NULL;
192 		mbfl_convert_filter *decoder     = NULL;
193 		const unsigned char *p, *q, *r;
194 		struct {
195 			mbfl_convert_filter encoder;
196 			mbfl_convert_filter decoder;
197 			const unsigned char *p;
198 			size_t pos;
199 		} bk, _bk;
200 
201 		/* output code filter */
202 		if (!(decoder = mbfl_convert_filter_new(
203 				&mbfl_encoding_wchar,
204 				string->encoding,
205 				mbfl_memory_device_output, 0, &device))) {
206 			return NULL;
207 		}
208 
209 		/* wchar filter */
210 		if (!(encoder = mbfl_convert_filter_new(
211 				string->encoding,
212 				&mbfl_encoding_wchar,
213 				mbfl_filter_output_null,
214 				NULL, NULL))) {
215 			mbfl_convert_filter_delete(decoder);
216 			return NULL;
217 		}
218 
219 		mbfl_memory_device_init(&device, length + 8, 0);
220 
221 		p = string->val;
222 
223 		/* search start position */
224 		for (q = string->val + from; p < q; p++) {
225 			(*encoder->filter_function)(*p, encoder);
226 		}
227 
228 		/* switch the drain direction */
229 		encoder->output_function = (output_function_t)decoder->filter_function;
230 		encoder->flush_function = (flush_function_t)decoder->filter_flush;
231 		encoder->data = decoder;
232 
233 		q = string->val + string->len;
234 
235 		/* save the encoder, decoder state and the pointer */
236 		mbfl_convert_filter_copy(decoder, &_bk.decoder);
237 		mbfl_convert_filter_copy(encoder, &_bk.encoder);
238 		_bk.p = p;
239 		_bk.pos = device.pos;
240 
241 		if (length > q - p) {
242 			length = q - p;
243 		}
244 
245 		if (length >= 20) {
246 			/* output a little shorter than "length" */
247 			/* XXX: the constant "20" was determined purely on the heuristics. */
248 			for (r = p + length - 20; p < r; p++) {
249 				(*encoder->filter_function)(*p, encoder);
250 			}
251 
252 			/* if the offset of the resulting string exceeds the length,
253 			 * then restore the state */
254 			if (device.pos > length) {
255 				p = _bk.p;
256 				device.pos = _bk.pos;
257 				if (decoder->filter_dtor)
258 					decoder->filter_dtor(decoder);
259 				if (encoder->filter_dtor)
260 					encoder->filter_dtor(encoder);
261 				mbfl_convert_filter_copy(&_bk.decoder, decoder);
262 				mbfl_convert_filter_copy(&_bk.encoder, encoder);
263 				bk = _bk;
264 			} else {
265 				/* save the encoder, decoder state and the pointer */
266 				mbfl_convert_filter_copy(decoder, &bk.decoder);
267 				mbfl_convert_filter_copy(encoder, &bk.encoder);
268 				bk.p = p;
269 				bk.pos = device.pos;
270 
271 				/* flush the stream */
272 				(*encoder->filter_flush)(encoder);
273 
274 				/* if the offset of the resulting string exceeds the length,
275 				 * then restore the state */
276 				if (device.pos > length) {
277 					if (bk.decoder.filter_dtor)
278 						bk.decoder.filter_dtor(&bk.decoder);
279 					if (bk.encoder.filter_dtor)
280 						bk.encoder.filter_dtor(&bk.encoder);
281 
282 					p = _bk.p;
283 					device.pos = _bk.pos;
284 					if (decoder->filter_dtor)
285 						decoder->filter_dtor(decoder);
286 					if (encoder->filter_dtor)
287 						encoder->filter_dtor(encoder);
288 					mbfl_convert_filter_copy(&_bk.decoder, decoder);
289 					mbfl_convert_filter_copy(&_bk.encoder, encoder);
290 					bk = _bk;
291 				} else {
292 					if (_bk.decoder.filter_dtor)
293 						_bk.decoder.filter_dtor(&_bk.decoder);
294 					if (_bk.encoder.filter_dtor)
295 						_bk.encoder.filter_dtor(&_bk.encoder);
296 
297 					p = bk.p;
298 					device.pos = bk.pos;
299 					if (decoder->filter_dtor)
300 						decoder->filter_dtor(decoder);
301 					if (encoder->filter_dtor)
302 						encoder->filter_dtor(encoder);
303 					mbfl_convert_filter_copy(&bk.decoder, decoder);
304 					mbfl_convert_filter_copy(&bk.encoder, encoder);
305 				}
306 			}
307 		} else {
308 			bk = _bk;
309 		}
310 
311 		/* detect end position */
312 		while (p < q) {
313 			(*encoder->filter_function)(*p, encoder);
314 
315 			if (device.pos > length) {
316 				/* restore filter */
317 				p = bk.p;
318 				device.pos = bk.pos;
319 				if (decoder->filter_dtor)
320 					decoder->filter_dtor(decoder);
321 				if (encoder->filter_dtor)
322 					encoder->filter_dtor(encoder);
323 				mbfl_convert_filter_copy(&bk.decoder, decoder);
324 				mbfl_convert_filter_copy(&bk.encoder, encoder);
325 				break;
326 			}
327 
328 			p++;
329 
330 			/* backup current state */
331 			mbfl_convert_filter_copy(decoder, &_bk.decoder);
332 			mbfl_convert_filter_copy(encoder, &_bk.encoder);
333 			_bk.pos = device.pos;
334 			_bk.p = p;
335 
336 			(*encoder->filter_flush)(encoder);
337 
338 			if (device.pos > length) {
339 				if (_bk.decoder.filter_dtor)
340 					_bk.decoder.filter_dtor(&_bk.decoder);
341 				if (_bk.encoder.filter_dtor)
342 					_bk.encoder.filter_dtor(&_bk.encoder);
343 
344 				/* restore filter */
345 				p = bk.p;
346 				device.pos = bk.pos;
347 				if (decoder->filter_dtor)
348 					decoder->filter_dtor(decoder);
349 				if (encoder->filter_dtor)
350 					encoder->filter_dtor(encoder);
351 				mbfl_convert_filter_copy(&bk.decoder, decoder);
352 				mbfl_convert_filter_copy(&bk.encoder, encoder);
353 				break;
354 			}
355 
356 			if (bk.decoder.filter_dtor)
357 				bk.decoder.filter_dtor(&bk.decoder);
358 			if (bk.encoder.filter_dtor)
359 				bk.encoder.filter_dtor(&bk.encoder);
360 
361 			p = _bk.p;
362 			device.pos = _bk.pos;
363 			if (decoder->filter_dtor)
364 				decoder->filter_dtor(decoder);
365 			if (encoder->filter_dtor)
366 				encoder->filter_dtor(encoder);
367 			mbfl_convert_filter_copy(&_bk.decoder, decoder);
368 			mbfl_convert_filter_copy(&_bk.encoder, encoder);
369 
370 			bk = _bk;
371 		}
372 
373 		decoder->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
374 		(*encoder->filter_flush)(encoder);
375 
376 		if (bk.decoder.filter_dtor)
377 			bk.decoder.filter_dtor(&bk.decoder);
378 		if (bk.encoder.filter_dtor)
379 			bk.encoder.filter_dtor(&bk.encoder);
380 
381 		result = mbfl_memory_device_result(&device, result);
382 
383 		mbfl_convert_filter_delete(encoder);
384 		mbfl_convert_filter_delete(decoder);
385 	}
386 
387 	return result;
388 }
389