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

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

#231に関連して、エンコーディング周りを見直し、Encoder/Decoderをストリーム用に特化。
UTF8Encodingをコンパイル可能にし、ビルドに含めるようにした。ただし、実装が不完全なためテストは不可。
(#231)

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