source: trunk/ab5.0/ablib/src/Classes/System/Text/Encoding.ab

Last change on this file was 702, checked in by イグトランス (egtra), 15 years ago

テキスト読み取り時、EOF周りの扱いの誤りを修正

File size: 14.7 KB
Line 
1/*!
2@file Classes/System/Text/Encoding.ab
3@brief Encodingクラスとそれに関係するクラスなどの宣言・定義
4*/
5
6Namespace System
7Namespace Text
8
9/*!
10@brief 各種の文字符号化(エンコーディング)を行うためのクラス
11@date 2007/12/07
12@auther Egtra
13
14なお、このクラスで、文字列の長さやバッファの大きさを指定するときには、
151 WCHAR = 2バイト(UTF-16符号単位)、1 Byte = 1バイトの単位で指定する。
16
17*/
18Class Encoding
19 Implements ICloneable
20Public
21 /*!
22 @brief 簡易的複製を作成する。
23 */
24 Virtual Function Clone() As Object
25 Clone = This
26 End Function
27
28' Override Function Equals(y As Object) As Boolean
29' End Function
30
31' Override Function GetHashCode() As Long
32' End Function
33
34Public
35 Sub Encoding()
36 End Sub
37
38 /*!
39 @brief 符号化して得られる文字列の長さを計算する。
40 @param[in] src 対象文字列
41 @param[in] srcCount srcの長さ(要素数単位)
42 @return 符号化して得られる文字列の長さ(要素数単位)
43 @date 2007/12/08
44 */
45 Function GetBytesCount(src As *WCHAR, srcCount As Long) As Long
46 If src = 0 Then
47 Throw New ArgumentNullException("src")
48 ElseIf srcCount < 0 Then
49 Throw New ArgumentOutOfRangeException("srcCount")
50 End If
51 Return GetBytesCountCore(src, srcCount)
52 End Function
53#ifdef UNICODE
54 /*!
55 @brief 符号化して得られる文字列の長さを計算する。
56 @param[in] src 対象文字列
57 @return 符号化して得られる文字列の長さ(要素数単位)
58 @date 2007/12/08
59 */
60 Function GetBytesCount(src As String) As Long
61 If ActiveBasic.IsNothing(src) Then
62 Throw New ArgumentNullException("src")
63 End If
64 Return GetBytesCountCore(StrPtr(src), src.Length)
65 End Function
66#endif
67
68Protected
69 /*!
70 @brief GetBytesCountの実装を行う。
71 @param[in] src 対象文字列
72 @param[in] srcCount srcの長さ(要素数単位)
73 @return 符号化して得られる文字列の長さ(要素数単位)
74 @date 2007/12/08
75 */
76 Virtual Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long
77 Dim s = New IO.Detail.WriteCountingNullStream
78 GetEncoder().Encode(src, srcCount, s, True)
79 GetBytesCountCore = s.WriteCount
80 If GetBytesCountCore < 0 Then
81 Throw New OverflowException
82 End If
83 End Function
84Public
85 /*!
86 @brief 符号化する。
87 @param[in] src 入力
88 @param[in] srcCount srcの長さ(要素数単位)
89 @param[out] dst 出力
90 @param[in] dstCount dstのバッファの大きさ(要素数単位)
91 @return dstに書き込まれた要素数
92 @date 2007/12/08
93 */
94 Function GetBytes(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
95 If src = 0 Then
96 Throw New ArgumentNullException("src")
97 ElseIf dst = 0 Then
98 Throw New ArgumentNullException("dst")
99 ElseIf srcCount < 0 Then
100 Throw New ArgumentOutOfRangeException("srcCount")
101 ElseIf dstCount < 0 Then
102 Throw New ArgumentOutOfRangeException("dstCount")
103 End If
104
105 Return GetBytesCore(src, srcCount, dst, dstCount)
106 End Function
107
108Protected
109 /*!
110 @brief GetBytesの処理を行う。
111 @param[in] src 入力
112 @param[in] srcCount srcの長さ(要素数単位)
113 @param[out] dst 出力
114 @param[in] dstCount dstのバッファの大きさ(要素数単位)
115 @return dstに書き込まれた要素数
116 @exception ArgumentException バッファの大きさが足りない
117 @date 2007/12/08
118 */
119 Virtual Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
120 Dim s = New IO.MemoryStream
121 GetEncoder().Encode(src, srcCount, s, True)
122 Dim size = s.Position()
123 If size > (dstCount As QWord) Then
124 Throw New ArgumentException("dstCount")
125 End If
126 GetBytesCore = size As Long
127 memcpy(dst, s.ToPointer(), size As SIZE_T)
128 End Function
129Public
130 /*!
131 @brief 復号して得られる文字列の長さを計算する。
132 @param[in] src 対象文字列
133 @param[in] srcCount srcの長さ(要素数単位)
134 @return 復号して得られる文字列の長さ(要素数単位)
135 @date 2007/12/08
136 */
137 Function GetCharsCount(src As *Byte, srcCount As Long) As Long
138 If src = 0 Then
139 Throw New ArgumentNullException("src")
140 ElseIf srcCount < 0 Then
141 Throw New ArgumentOutOfRangeException("srcCount")
142 End If
143 Return GetCharsCountCore(src, srcCount)
144 End Function
145
146Protected
147 /*!
148 @brief GetCharsCountの処理を行う。
149 @param[in] src 対象文字列
150 @param[in] srcCount srcの長さ(要素数単位)
151 @return 符号化して得られる文字列の長さ(要素数単位)
152 @date 2007/12/08
153 */
154 Virtual Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long
155 Dim s = New IO.MemoryStream(src, srcCount)
156 Dim l = New Collections.Generic.List<WCHAR>
157 GetDecoder().Decode(l, s)
158 GetCharsCountCore = l.Count
159 End Function
160Public
161 /*!
162 @brief 復号する。
163 @param[in] src 入力
164 @param[in] srcCount srcの長さ(要素数単位)
165 @param[out] dst 出力
166 @param[in] dstCount srcのバッファの大きさ(要素数単位)
167 @return dstに書き込まれた要素数
168 @date 2007/12/08
169 */
170 Function GetChars(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
171 If dst = 0 Then
172 Throw New ArgumentNullException("dst")
173 ElseIf src = 0 Then
174 Throw New ArgumentNullException("src")
175 ElseIf dstCount < 0 Then
176 Throw New ArgumentOutOfRangeException("dstCount")
177 ElseIf srcCount < 0 Then
178 Throw New ArgumentOutOfRangeException("srcCount")
179 End If
180
181 Return GetCharsCore(src, srcCount, dst, dstCount)
182 End Function
183
184Protected
185 /*!
186 @brief GetCharsの処理を行う。
187 @param[in] src 入力
188 @param[in] srcCount srcの長さ(要素数単位)
189 @param[out] dst 出力
190 @param[in] dstCount dstのバッファの大きさ(要素数単位)
191 @return dstに書き込まれた要素数
192 @exception ArgumentException バッファの大きさが足りない
193 @date 2007/12/08
194 */
195 Virtual Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
196 Dim s = New IO.MemoryStream(src, srcCount)
197 Dim l = New Collections.Generic.List<WCHAR>
198 GetDecoder().Decode(l, s)
199 If l.Count > dstCount Then
200 Throw New ArgumentException("dstCount")
201 End If
202 Dim p As *WCHAR
203 p = l
204 memcpy(dst, p, (l.Count As SIZE_T) * 2)
205 End Function
206Public
207#ifdef UNICODE
208 /*!
209 @brief 復号し、Stringで結果を返す。
210 @param[in] src 入力
211 @param[in] srcCount srcの長さ(要素数単位)
212 @return 変換結果の文字列
213 @date 2007/12/08
214 */
215 Function GetString(src As *Byte, srcCount As Long) As String
216 If src = 0 Then
217 Throw New ArgumentNullException("src")
218 ElseIf srcCount < 0 Then
219 Throw New ArgumentOutOfRangeException("srcCount")
220 End If
221 GetString = getStringCore(src, srcCount)
222 End Function
223
224Private
225 Function getStringCore(src As *Byte, srcCount As Long) As String
226 Dim sb = New StringBuilder
227 Dim bufCount = GetMaxCharCount(srcCount)
228 sb.Length = bufCount
229 Dim len = GetCharsCore(src, srcCount, StrPtr(sb), bufCount)
230 sb.Length = len
231 getStringCore = sb.ToString()
232 End Function
233#endif
234
235Public
236 /*!
237 @brief 復号器を取得する。
238 */
239 Abstract Function GetDecoder() As Decoder
240
241 /*!
242 @brief 符号器を取得する。
243 */
244 Abstract Function GetEncoder() As Encoder
245
246 /*!
247 @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。
248 */
249 Abstract Function GetMaxByteCount(srcCount As Long) As Long
250
251 /*!
252 @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。
253 */
254 Abstract Function GetMaxCharCount(srcCount As Long) As Long
255
256 /*!
257 @brief 符号化された文字列の先頭につける識別文字列の取得
258 ようするにUTFのBOM。
259 */
260 Virtual Function GetPreamble() As *Byte
261 Return 0
262 End Function
263
264 /*!
265 @brief GetPreambleの配列の要素数。
266 */
267 Virtual Function GetPreambleLength() As Long
268 Return 0
269 End Function
270
271Public
272' Abstract Function BodyName() As String
273' Abstract Function HeaderName() As String
274
275 /*!
276 @brief コードページの取得。
277 */
278' Abstract Function CodePage() As Long
279 /*!
280 @brief 最も厳密に対応するWindowsコードページの取得。
281 */
282' Abstract Function WindowsCodePage() As Long
283
284Public
285 /*!
286 @brief この符号化形式の名前の取得。
287 */
288' Abstract Function EncodingName() As String
289
290 /*!
291 @brief この符号化形式のIANA登録名の取得。
292 */
293' Abstract Function WebName() As String
294
295' Abstract Function IsBrowserDisplay() As Boolean
296' Abstract Function IsBrowserSave() As Boolean
297' Abstract Function IsMailNewsDisplay() As Boolean
298' Abstract Function IsMailNewsSave() As Boolean
299
300 /*!
301 @brief この符号化形式が、1バイト文字だけを使う(複数バイト文字を使わない)かどうか。
302 */
303' Abstract Function IsSingleByte() As Boolean
304
305 'GetPreamble
306
307 /*!
308 @brief ある符号化文字列から別の符号化文字列へ変換する。
309 @param[in] srcEncoding 入力の符号化方式
310 @param[in] dstEncoding 出力の符号化方式
311 @param[in] bytes 入力文字列
312 @param[in] size バイト単位での文字列の長さ
313 @return 出力文字列
314 @exception ArgumentNullException srcEncoding, dstEncoding, bytesの少なくとも1つ以上がNothing/NULLのとき。
315 @exception ArgumentOutOfRangeException sizeが明らかに範囲外(負の値など)のとき。
316 */
317' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, size As Long) As *Byte
318' End Function
319
320' Static Function Convert(srcEncoding As Encoding, dstEncoding As Encoding, bytes As *Byte, index As Long, count As Long) As *Byte
321' End Function
322
323 /*!
324 @brief 指定したコードページ用のEncodingインスタンスの取得。
325 */
326' Static Function GetEncoding(codepage As Long) As Encoding
327' End Function
328 /*!
329 @brief 指定した符号化形式名用のEncodingインスタンスの取得。
330 */
331' Static Function GetEncoding(name As String) As Encoding
332' End Function
333 /*!
334 @brief システムで標準のANSIコードページ用のEncodingインスタンスの取得。
335 */
336 Static Function Default() As Encoding
337 End Function
338 /*!
339 @brief UTF-8用のEncodingインスタンスの取得。
340 */
341 Static Function UTF8() As Encoding
342 End Function
343 /*!
344 @brief UTF-16LE用のEncodingインスタンスの取得。
345 */
346 Static Function UTF16() As Encoding
347 End Function
348 /*!
349 @brief UTF-16BE用のEncodingインスタンスの取得。
350 */
351 Static Function UTF16BE() As Encoding
352 End Function
353End Class
354
355/*!
356@brief 復号を行うクラス
357@date 2009/01/12
358@auther Egtra
359内部処理用
360*/
361Class Decoder
362Public
363 /*!
364 @brief 復号する。
365 @param[out] dst 出力先
366 @param[in] s 入力元
367 @return sを最後 (EOF) まで読んだらFalse、まだあればTrue。
368 */
369 Function Decode(dst As Collections.Generic.List<WCHAR>, s As IO.Stream) As Boolean
370 Decode = DecodeImpl(dst, s)
371 End Function
372
373Protected
374 Abstract Function DecodeImpl(dst As Collections.Generic.List<WCHAR>, s As IO.Stream) As Boolean
375End Class
376
377/*!
378@brief 符号化を行うクラス
379@date 2009/01/12
380@auther Egtra
381内部処理用
382*/
383Class Encoder
384Public
385 Sub Encode(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
386 EncodeImpl(src, size, s, last)
387 End Sub
388
389Protected
390 Abstract Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
391End Class
392
393Enum NormalizationForm
394 FormC
395 FormD
396 FormKC
397 FormKD
398End Enum
399
400Namespace Detail
401
402/*!
403@brief WideCharToMultiByte/MultiByteToWideCharで変換を行うエンコーディング。
404DBCS/SBCS限定。UTF-8やUTF-7は非対応。
405*/
406Class WindowsCodePageEncoding
407 Inherits Encoding
408Public
409 Sub WindowsCodePageEncoding(codepage As DWord)
410 cp = codepage
411 End Sub
412
413 Override Function GetHashCode() As Long
414 GetHashCode = cp As Long
415 End Function
416
417 Override Function Equals(x As Object) As Boolean
418 If GetType().Equals(x.GetType()) Then
419 Dim xe = x As WindowsCodePageEncoding
420 Equals = cp = xe.cp
421 Else
422 Equals = False
423 End If
424 End Function
425
426 Override Function GetDecoder() As Decoder
427 GetDecoder = New WindowsCodePageDecoder(cp)
428 End Function
429
430 Override Function GetEncoder() As Encoder
431 GetEncoder = New WindowsCodePageEncoder(cp)
432 End Function
433
434 /*!
435 @brief ある長さの文字列を符号化して得られるバイト列の最大の長さを返す。
436 */
437 Override Function GetMaxByteCount(srcCount As Long) As Long
438 GetMaxByteCount = srcCount * 2
439 End Function
440
441 /*!
442 @brief ある長さのバイト列を復号して得られる文字列の最大の長さを返す。
443 */
444 Override Function GetMaxCharCount(srcCount As Long) As Long
445 GetMaxCharCount = srcCount
446 End Function
447
448Protected
449 Override Function GetBytesCountCore(src As *WCHAR, srcCount As Long) As Long
450 GetBytesCountCore = WideCharToMultiByte(cp, 0, src, srcCount, 0, 0, 0, 0)
451 If srcCount <> 0 And GetBytesCountCore = 0 Then
452 ActiveBasic.Windows.ThrowWithLastError()
453 End If
454 End Function
455
456 Override Function GetBytesCore(src As *WCHAR, srcCount As Long, dst As *Byte, dstCount As Long) As Long
457 GetBytesCore = WideCharToMultiByte(cp, 0, src, srcCount, dst As PCSTR, dstCount, 0, 0)
458 If srcCount <> 0 And GetBytesCore = 0 Then
459 ActiveBasic.Windows.ThrowWithLastError()
460 End If
461 End Function
462
463 Override Function GetCharsCountCore(src As *Byte, srcCount As Long) As Long
464 GetCharsCountCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, 0, 0)
465 If srcCount <> 0 And GetCharsCountCore = 0 Then
466 ActiveBasic.Windows.ThrowWithLastError()
467 End If
468 End Function
469
470 Override Function GetCharsCore(src As *Byte, srcCount As Long, dst As *WCHAR, dstCount As Long) As Long
471 GetCharsCore = MultiByteToWideChar(cp, 0, src As PCSTR, srcCount, dst, dstCount)
472 If srcCount <> 0 And GetCharsCore = 0 Then
473 ActiveBasic.Windows.ThrowWithLastError()
474 End If
475 End Function
476
477Private
478 cp As DWord
479End Class
480
481/*!
482@brief WideCharToMultiByteで復号化を行うクラス
483@date 2009/01/12
484@auther Egtra
485内部処理用
486*/
487Class WindowsCodePageEncoder
488 Inherits Encoder
489Public
490 Sub WindowsCodePageEncoder(codepage As DWord)
491 cp = codepage
492 End Sub
493
494Protected
495 Override Sub EncodeImpl(src As *WCHAR, size As SIZE_T, s As IO.Stream, last As Boolean)
496 ' サロゲートペアや結合文字列 (Combining Character Sequence)の途中でバッファが途切れている場合に対応する
497 ' ToDo: エラー処理
498 Dim mbLen = WideCharToMultiByte(cp, 0, src, size As Long, 0, 0, 0, 0)
499 Dim mbBuf = GC_malloc_atomic(mbLen)
500 WideCharToMultiByte(cp, 0, src, size As Long, mbBuf, mbLen, 0, 0)
501 s.Write(mbBuf, 0, mbLen)
502 End Sub
503
504Private
505 cp As DWord
506End Class
507
508/*!
509@brief MultiByteToWideCharで復号化を行うクラス
510@date 2009/01/12
511@auther Egtra
512内部処理用
513*/
514Class WindowsCodePageDecoder
515 Inherits Decoder
516Public
517 Sub WindowsCodePageDecoder(codepage As DWord)
518 cp = codepage
519 End Sub
520
521Protected
522 Override Function DecodeImpl(dst As Collections.Generic.List<WCHAR>, s As IO.Stream) As Boolean
523 Dim i As Long
524 For i = 0 To DefalultDecodingBufferSize - 1 'ELM
525 Dim len As Long
526 Dim buf[1] As CHAR
527 Dim t = s.ReadByte()
528 If t = -1 Then
529 DecodeImpl = False
530 Exit Function
531 End If
532 buf[0] = t As CHAR
533 If IsDBCSLeadByteEx(cp, buf[0]) Then
534 t = s.ReadByte()
535 If t = -1 Then
536 dst.Add(&hfffd As WCHAR)
537 Exit Function
538 End If
539 buf[1] = t As CHAR
540 len = 2
541 Else
542 len = 1
543 End If
544 Dim wc As WCHAR
545 If MultiByteToWideChar(cp, 0, buf, len, VarPtr(wc), 1) = 0 Then
546 dst.Add(&hFFFD As WCHAR)
547 Else
548 dst.Add(wc)
549 End If
550 Next
551 DecodeImpl = True
552 End Function
553
554Private
555 cp As DWord
556End Class
557
558Const DefalultDecodingBufferSize = 16384
559
560End Namespace
561
562End Namespace 'Text
563End Namespace 'System
Note: See TracBrowser for help on using the repository browser.